<script setup lang="ts">
// 引入Vue相关API
import { ref, onMounted, onBeforeUnmount, nextTick, computed } from 'vue'

// 引入vue-router用于页面跳转
import { useRouter, useRoute } from 'vue-router'
// 引入SparkMD5用于文件校验
// 注意：实际项目中需要安装 spark-md5 依赖：npm install spark-md5
// import SparkMD5 from 'spark-md5'
// 引入用户信息工具
import { getUserDisplayName, getUserAvatar } from '../../utils/userStore'
// 引入统一数据管理
import { addCommunityPost } from '../../utils/dataSync'

// 节流函数，限制函数执行频率
function throttle(fn: Function, delay: number) {
  let lastCall = 0
  return function(...args: any[]) {
    const now = new Date().getTime()
    if (now - lastCall < delay) return
    lastCall = now
    return fn(...args)
  }
}

// 防抖函数，延迟执行函数，避免频繁触发
function debounce(fn: Function, delay: number) {
  // 定义一个定时器变量
  let timer: number | null = null
  
  // 返回一个闭包函数
  return function(...args: any[]) {
    // 如果已有定时器，则清除
    if (timer) clearTimeout(timer)
    
    // 设置新的定时器，延迟执行传入的函数
    timer = window.setTimeout(() => {
      fn(...args)
      // 执行后清空定时器
      timer = null
    }, delay) as unknown as number
  }
}

// Toast提示相关变量
const showToast = ref(false);         // 是否显示提示
const toastMessage = ref('');         // 提示信息
const toastType = ref<'success' | 'error' | 'warning' | 'info'>('info'); // 提示类型

// 显示Toast提示
function showToastMessage(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info', duration = 3000) {
  toastMessage.value = message;
  toastType.value = type;
  showToast.value = true;
  
  // 自动隐藏
  setTimeout(() => {
    showToast.value = false;
  }, duration);
}

// 定义tab列表
const tabs = [
  { label: '发现', value: 'discover' }, // 发现tab
  { label: '韵动圈', value: 'circle' }  // 韵动圈tab
]
// 当前选中的tab，默认显示发现，类型为ref<string>
const activeTab = ref<string>('discover')
// 处理tab切换
function handleTabChange(tabValue: string) {
  // 如果切换到韵动圈tab，重置分页数据并加载
  if (tabValue === 'circle') {
    console.log('切换到韵动圈tab，初始化数据')
    initData()
    
    // 切换后延迟检查一次滚动位置
    setTimeout(() => {
      console.log('切换tab后检查滚动位置')
      handleScroll()
    }, 500)
  }
  // 如果切换到发现tab，初始化发现页数据
  else if (tabValue === 'discover') {
    console.log('切换到发现tab，初始化数据')
    initDiscoverData()
    
    // 切换后延迟检查一次滚动位置
    setTimeout(() => {
      console.log('切换tab后检查滚动位置')
      handleScroll()
    }, 500)
  }
}

// 搜索框内容
const search = ref('')

// 搜索结果
const searchResults = ref<UserType[]>([])

// 是否正在搜索中
const isSearching = ref(false)

// 使用计算属性过滤用户列表
const filteredUsers = computed(() => {
  if (!search.value.trim()) {
    // 如果搜索框为空，返回所有用户
    return displayUserList.value
  }
  
  // 如果在搜索中，返回搜索结果
  return searchResults.value
})

// 处理搜索输入，使用防抖函数包装
const handleSearchInput = debounce(() => {
  const searchTerm = search.value.trim().toLowerCase()
  
  if (!searchTerm) {
    // 如果搜索词为空，重置搜索状态
    searchResults.value = []
    isSearching.value = false
    // 重新初始化发现页数据
    if (activeTab.value === 'discover') {
      initDiscoverData()
    }
    return
  }
  
  console.log('执行搜索:', searchTerm)
  isSearching.value = true
  
  // 执行模糊搜索
  const results = users.value.filter(user => 
    user.name.toLowerCase().includes(searchTerm)
  )
  
  console.log('搜索结果:', results.length, '条匹配')
  searchResults.value = results
  
  // 如果当前是发现页，更新显示的用户列表
  if (activeTab.value === 'discover') {
    displayUserList.value = results
    // 重置分页状态
    discoverCurrentPage.value = 1
    discoverNoMoreData.value = true // 搜索结果不需要分页加载
  }
}, 300) // 300毫秒的防抖延迟

// 监听搜索框输入
function onSearchInput() {
  handleSearchInput()
}

// 高亮显示搜索关键词
function highlightKeyword(text: string, keyword: string): string {
  if (!keyword.trim()) {
    return text
  }
  
  // 转义正则表达式中的特殊字符
  const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  
  // 创建正则表达式，使用 'i' 标志进行不区分大小写的匹配
  const regex = new RegExp(`(${escapedKeyword})`, 'gi')
  
  // 替换匹配的文本为带有高亮样式的HTML
  return text.replace(regex, '<span class="highlight">$1</span>')
}

// 用户类型声明
interface UserType {
  avatar: string;
  name: string;
  level: number;
  followed: boolean;
}

// 新增媒体类型定义
interface MediaType {
  file: File | null; // 文件对象
  url: string; // 预览URL
  type: 'image' | 'video'; // 媒体类型
  size: number; // 文件大小（字节）
  name: string; // 文件名
  removed?: boolean; // 是否已被移除（用于控制视频显示）
}

// 用户列表数据，模拟数据，使用ref包裹为响应式
const users = ref<UserType[]>([
  {
    avatar: 'https://randomuser.me/api/portraits/women/1.jpg', // 头像
    name: '用户031256', // 用户名
    level: 50, // 等级
    followed: false // 是否已关注
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/1.jpg',
    name: '运动博主052',
    level: 40,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/1.jpg',
    name: '运动博主071',
    level: 36,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/2.jpg',
    name: '运动博主163',
    level: 26,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/1.jpg',
    name: '运动博主044',
    level: 33,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/2.jpg',
    name: '运动博主033',
    level: 15,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/3.jpg', // 添加新用户数据
    name: '健身达人088', // 用户名
    level: 45, // 等级
    followed: false // 是否已关注
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/4.jpg', // 添加新用户数据
    name: '瑜伽教练112', // 用户名
    level: 56, // 等级
    followed: false // 是否已关注
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/5.jpg', // 添加新用户数据
    name: '马拉松选手065', // 用户名
    level: 48, // 等级
    followed: false // 是否已关注
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/6.jpg', // 添加新用户数据
    name: '健身教练121', // 用户名
    level: 60, // 等级
    followed: false // 是否已关注
  },
  // 添加更多用户数据
  {
    avatar: 'https://randomuser.me/api/portraits/men/7.jpg',
    name: '游泳爱好者098',
    level: 38,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/8.jpg',
    name: '舞蹈老师057',
    level: 52,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/9.jpg',
    name: '健身小白099',
    level: 22,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/10.jpg',
    name: '瑜伽达人078',
    level: 47,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/11.jpg',
    name: '铁人三项007',
    level: 65,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/12.jpg',
    name: '普拉提爱好者023',
    level: 31,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/13.jpg',
    name: '攀岩爱好者045',
    level: 42,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/14.jpg',
    name: '柔道选手038',
    level: 55,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/15.jpg',
    name: '拳击教练056',
    level: 58,
    followed: false
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/16.jpg',
    name: '健身达人127',
    level: 43,
    followed: false
  }
])

// 动态项类型定义
interface CircleItem {
  avatar: string; // 头像
  name: string; // 用户名
  date: string; // 日期
  sportType: string; // 运动类型
  distance: string; // 距离
  time: string; // 时间
  calorie: string; // 消耗
  images: string[]; // 媒体URL列表
  mediaTypes?: string[]; // 媒体类型列表
  descTitle: string; // 标题
  desc: string; // 描述
  like: number; // 点赞数
  comment: number; // 评论数
  id?: string; // 唯一标识符
}

// 韵动圈动态列表数据
const circleList = ref<CircleItem[]>([
  {
    avatar: 'https://randomuser.me/api/portraits/women/1.jpg', // 头像
    name: '用户031256', // 用户名
    date: '2024-12-01', // 日期
    sportType: '户外跑步', // 运动类型
    distance: '3.56km', // 距离
    time: '00:38:05', // 时间
    calorie: '212千卡', // 消耗
    images: [
      'https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=400&q=80' // 运动照片
    ],
    descTitle: '每日训练', // 标题
    desc: '今日运动打卡，保持完美身材', // 描述
    like: 12, // 点赞数
    comment: 3 // 评论数
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/2.jpg',
    name: '运动博主033',
    date: '2024-12-01',
    sportType: '户外骑行',
    distance: '5.20km',
    time: '01:12:10',
    calorie: '320千卡',
    images: [
      'https://images.unsplash.com/photo-1517649763962-0c623066013b?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '骑行冲刺',
    desc: '挑战极限，享受速度与激情',
    like: 8,
    comment: 1
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/3.jpg', // 添加新动态数据
    name: '健身达人088', 
    date: '2024-12-02', 
    sportType: '力量训练', 
    distance: '0.00km', 
    time: '01:30:00', 
    calorie: '458千卡', 
    images: [
      'https://images.unsplash.com/photo-1541534741688-6078c6bfb5c5?auto=format&fit=crop&w=400&q=80' 
    ],
    descTitle: '胸肌训练日', 
    desc: '今天完成了10组卧推，感觉很棒', 
    like: 25, 
    comment: 7 
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/4.jpg', // 添加新动态数据
    name: '瑜伽教练112', 
    date: '2024-12-02', 
    sportType: '瑜伽', 
    distance: '0.00km', 
    time: '00:45:30', 
    calorie: '180千卡', 
    images: [
      'https://images.unsplash.com/photo-1506126613408-eca07ce68773?auto=format&fit=crop&w=400&q=80' 
    ],
    descTitle: '晨间瑜伽', 
    desc: '早晨的阳光瑜伽，让一天充满正能量', 
    like: 36, 
    comment: 12 
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/5.jpg', // 添加新动态数据
    name: '马拉松选手065', 
    date: '2024-12-03', 
    sportType: '长跑', 
    distance: '21.5km', 
    time: '01:56:22', 
    calorie: '1256千卡', 
    images: [
      'https://images.unsplash.com/photo-1452626038306-9aae5e071dd3?auto=format&fit=crop&w=400&q=80' 
    ],
    descTitle: '半程马拉松训练', 
    desc: '今天完成半马训练，为下个月的全马比赛做准备', 
    like: 48, 
    comment: 15 
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/6.jpg',
    name: '健身教练121',
    date: '2024-12-04',
    sportType: 'HIIT训练',
    distance: '0.00km',
    time: '00:35:45',
    calorie: '380千卡',
    images: [
      'https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '高强度间歇训练',
    desc: '完成今天的HIIT，燃脂效果超级棒，大家也要坚持哦！',
    like: 52,
    comment: 16
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/7.jpg',
    name: '游泳爱好者098',
    date: '2024-12-04',
    sportType: '游泳',
    distance: '1.5km',
    time: '00:42:18',
    calorie: '328千卡',
    images: [
      'https://images.unsplash.com/photo-1565992441121-4367c2967103?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '自由泳训练',
    desc: '今天在泳池完成了1.5公里，呼吸节奏掌握得越来越好了',
    like: 31,
    comment: 8
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/8.jpg',
    name: '舞蹈老师057',
    date: '2024-12-05',
    sportType: '舞蹈',
    distance: '0.00km',
    time: '01:10:00',
    calorie: '410千卡',
    images: [
      'https://images.unsplash.com/photo-1508700929628-666bc8bd84ea?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '爵士舞练习',
    desc: '新编舞完成！下周课堂要教的内容，小伙伴们准备好了吗？',
    like: 47,
    comment: 14
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/9.jpg',
    name: '健身小白099',
    date: '2024-12-05',
    sportType: '健身',
    distance: '0.00km',
    time: '01:00:00',
    calorie: '365千卡',
    images: [
      'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '健身第三周',
    desc: '坚持健身已经三周了，感觉自己的身体素质有明显提升，继续加油！',
    like: 23,
    comment: 5
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/10.jpg',
    name: '瑜伽达人078',
    date: '2024-12-06',
    sportType: '高温瑜伽',
    distance: '0.00km',
    time: '00:50:00',
    calorie: '420千卡',
    images: [
      'https://images.unsplash.com/photo-1552196563-55cd4e45efb3?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '高温瑜伽体验',
    desc: '第一次尝试高温瑜伽，在38度的环境下练习，排汗特别多，感觉身体被彻底净化了',
    like: 39,
    comment: 11
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/11.jpg',
    name: '铁人三项007',
    date: '2024-12-07',
    sportType: '铁人三项',
    distance: '51.5km',
    time: '03:25:40',
    calorie: '2580千卡',
    images: [
      'https://images.unsplash.com/photo-1520877880798-5ee004e3f11e?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '周末铁三训练',
    desc: '完成了游泳1.5km、自行车40km、跑步10km的训练，为下个月的比赛做准备',
    like: 76,
    comment: 22
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/12.jpg',
    name: '普拉提爱好者023',
    date: '2024-12-08',
    sportType: '普拉提',
    distance: '0.00km',
    time: '00:55:00',
    calorie: '260千卡',
    images: [
      'https://images.unsplash.com/photo-1518611012118-696072aa579a?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '核心训练',
    desc: '今天专注练习核心力量，普拉提真的很锻炼腹部肌群和平衡能力',
    like: 28,
    comment: 6
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/13.jpg',
    name: '攀岩爱好者045',
    date: '2024-12-09',
    sportType: '攀岩',
    distance: '0.00km',
    time: '01:30:00',
    calorie: '520千卡',
    images: [
      'https://images.unsplash.com/photo-1522163182402-834f871fd851?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '攀岩新高度',
    desc: '今天终于完成了困扰我一个月的红色路线，手臂和核心力量的训练终于有了成果',
    like: 41,
    comment: 13
  },
  {
    avatar: 'https://randomuser.me/api/portraits/women/14.jpg',
    name: '柔道选手038',
    date: '2024-12-10',
    sportType: '柔道',
    distance: '0.00km',
    time: '01:45:00',
    calorie: '560千卡',
    images: [
      'https://images.unsplash.com/photo-1587909209111-5097ee578ec3?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '技术训练日',
    desc: '今天专注练习过肩摔技术，教练说我的重心控制有很大进步',
    like: 35,
    comment: 9
  },
  {
    avatar: 'https://randomuser.me/api/portraits/men/15.jpg',
    name: '拳击教练056',
    date: '2024-12-11',
    sportType: '拳击',
    distance: '0.00km',
    time: '01:20:00',
    calorie: '680千卡',
    images: [
      'https://images.unsplash.com/photo-1549824506-b7045a1bca6e?auto=format&fit=crop&w=400&q=80'
    ],
    descTitle: '拳击组合训练',
    desc: '今天教学生新的拳法组合，左直拳-右摆拳-左勾拳-闪躲-右上勾拳，看看视频中的示范',
    like: 63,
    comment: 19
  }
])

// 分页相关变量 - 韵动圈
const pageSize = ref(2) // 每页显示数量
const currentPage = ref(1) // 当前页码
const loading = ref(false) // 加载状态
const noMoreData = ref(false) // 是否还有更多数据

// 发现页分页相关变量
const discoverPageSize = ref(5) // 发现页每页显示数量
const discoverCurrentPage = ref(1) // 发现页当前页码
const discoverLoading = ref(false) // 发现页加载状态
const discoverNoMoreData = ref(false) // 发现页是否还有更多数据

// 用于展示的分页后的动态数据
const displayCircleList = ref<any[]>([])

// 用于展示的分页后的用户数据
const displayUserList = ref<UserType[]>([])

// 初始化韵动圈数据
function initData() {
  // 重置分页状态
  currentPage.value = 1
  noMoreData.value = false
  displayCircleList.value = []
  
  // 加载第一页数据
  loadMoreData()
}

// 初始化发现页数据
function initDiscoverData() {
  // 如果有搜索内容，不重置搜索结果
  if (search.value.trim()) {
    return
  }
  
  // 重置分页状态
  discoverCurrentPage.value = 1
  discoverNoMoreData.value = false
  displayUserList.value = []
  
  // 加载第一页数据
  loadMoreDiscoverData()
}

// 加载更多韵动圈数据
function loadMoreData() {
  // 如果正在加载或没有更多数据，则直接返回
  if (loading.value || noMoreData.value) {
    console.log('已在加载中或没有更多数据，跳过加载')
    return
  }
  
  // 设置加载状态
  loading.value = true
  console.log('开始加载更多数据，当前页码:', currentPage.value)
  
  // 模拟网络请求延迟
  setTimeout(() => {
    try {
      // 计算起始和结束索引
      const start = (currentPage.value - 1) * pageSize.value
      const end = start + pageSize.value
      
      console.log('加载数据范围:', start, '至', end, '总数据量:', circleList.value.length)
      
      // 获取当前页的数据
      const newData = circleList.value.slice(start, end)
      console.log('获取到新数据条数:', newData.length)
      
      // 如果没有新数据，表示已经加载完所有数据
      if (newData.length === 0) {
        console.log('没有更多数据了')
        noMoreData.value = true
      } else {
        // 添加新数据到显示列表
        displayCircleList.value = [...displayCircleList.value, ...newData]
        console.log('当前显示数据总条数:', displayCircleList.value.length, '/', circleList.value.length)
        // 页码加1
        currentPage.value++
        console.log('页码增加到:', currentPage.value)
        
        // 如果已经加载完所有数据，设置noMoreData为true
        if (displayCircleList.value.length >= circleList.value.length) {
          console.log('已加载全部数据')
          noMoreData.value = true
        }
      }
    } catch (error) {
      console.error('加载数据时出错:', error)
    } finally {
      // 重置加载状态
      loading.value = false
      console.log('加载状态重置为false')
    }
  }, 500) // 模拟加载延迟，减少等待时间
}

// 加载更多发现页数据
function loadMoreDiscoverData() {
  // 如果正在加载或没有更多数据，则直接返回
  if (discoverLoading.value || discoverNoMoreData.value) {
    console.log('发现页：已在加载中或没有更多数据，跳过加载')
    return
  }
  
  // 设置加载状态
  discoverLoading.value = true
  console.log('发现页：开始加载更多数据，当前页码:', discoverCurrentPage.value)
  
  // 模拟网络请求延迟
  setTimeout(() => {
    try {
      // 计算起始和结束索引
      const start = (discoverCurrentPage.value - 1) * discoverPageSize.value
      const end = start + discoverPageSize.value
      
      console.log('发现页：加载数据范围:', start, '至', end, '总数据量:', users.value.length)
      
      // 获取当前页的数据
      const newData = users.value.slice(start, end)
      console.log('发现页：获取到新数据条数:', newData.length)
      
      // 如果没有新数据，表示已经加载完所有数据
      if (newData.length === 0) {
        console.log('发现页：没有更多数据了')
        discoverNoMoreData.value = true
      } else {
        // 添加新数据到显示列表
        displayUserList.value = [...displayUserList.value, ...newData]
        console.log('发现页：当前显示数据总条数:', displayUserList.value.length, '/', users.value.length)
        // 页码加1
        discoverCurrentPage.value++
        console.log('发现页：页码增加到:', discoverCurrentPage.value)
        
        // 如果已经加载完所有数据，设置noMoreData为true
        if (displayUserList.value.length >= users.value.length) {
          console.log('发现页：已加载全部数据')
          discoverNoMoreData.value = true
        }
      }
    } catch (error) {
      console.error('发现页：加载数据时出错:', error)
    } finally {
      // 重置加载状态
      discoverLoading.value = false
      console.log('发现页：加载状态重置为false')
    }
  }, 500) // 模拟加载延迟，减少等待时间
}

// 触底检测函数
function handleScroll() {
  // 如果在韵动圈tab，处理韵动圈的触底加载
  if (activeTab.value === 'circle') {
    // 如果正在加载或没有更多数据，则不处理
    if (loading.value || noMoreData.value) {
      console.log('韵动圈：已在加载中或没有更多数据，跳过触底检测')
      return
    }
    
    // 获取滚动容器和位置信息
    const scrollTop = window.scrollY || document.documentElement.scrollTop
    const windowHeight = window.innerHeight
    const documentHeight = document.documentElement.scrollHeight
    
    // 计算距离底部的距离（像素）
    const distanceToBottom = documentHeight - scrollTop - windowHeight
    
    // 调试信息
    console.log('韵动圈：滚动位置:', scrollTop)
    console.log('韵动圈：窗口高度:', windowHeight)
    console.log('韵动圈：文档高度:', documentHeight)
    console.log('韵动圈：距离底部:', distanceToBottom)
    
    // 当距离底部小于阈值时触发加载（使用较大的阈值以提前加载）
    const THRESHOLD = 100
    if (distanceToBottom < THRESHOLD) {
      console.log('韵动圈：触发加载更多，距离底部:', distanceToBottom)
      loadMoreData()
    }
  } 
  // 如果在发现tab，处理发现页的触底加载
  else if (activeTab.value === 'discover') {
    // 如果正在加载或没有更多数据，则不处理
    if (discoverLoading.value || discoverNoMoreData.value) {
      console.log('发现页：已在加载中或没有更多数据，跳过触底检测')
      return
    }
    
    // 获取滚动容器和位置信息
    const scrollTop = window.scrollY || document.documentElement.scrollTop
    const windowHeight = window.innerHeight
    const documentHeight = document.documentElement.scrollHeight
    
    // 计算距离底部的距离（像素）
    const distanceToBottom = documentHeight - scrollTop - windowHeight
    
    // 调试信息
    console.log('发现页：滚动位置:', scrollTop)
    console.log('发现页：窗口高度:', windowHeight)
    console.log('发现页：文档高度:', documentHeight)
    console.log('发现页：距离底部:', distanceToBottom)
    
    // 当距离底部小于阈值时触发加载（使用较大的阈值以提前加载）
    const THRESHOLD = 100
    if (distanceToBottom < THRESHOLD) {
      console.log('发现页：触发加载更多，距离底部:', distanceToBottom)
      loadMoreDiscoverData()
    }
  }
}

// 使用节流函数包装滚动处理函数
const throttledHandleScroll = throttle(handleScroll, 200)

// 获取路由实例
const router = useRouter()
// 获取当前路由
const route = useRoute()

// 页面加载时，检查是否有从详情页传回的用户关注状态
onMounted(() => {
  // 从localStorage加载用户关注状态
  loadFollowedUsersFromStorage();
  
  // 从localStorage加载用户发布的动态
  loadCircleListFromStorage();
  
  // 初始化韵动圈数据
  initData()
  
  // 初始化发现页数据
  initDiscoverData()
  
  // 添加滚动事件监听，使用节流函数限制触发频率
  window.addEventListener('scroll', throttledHandleScroll)
  document.addEventListener('scroll', throttledHandleScroll)
  
  // 初始加载后检查一次滚动位置，以防内容不足一屏
  setTimeout(() => {
    console.log('初始检查滚动位置')
    handleScroll()
  }, 1000)
  
  // 检查路由参数中是否包含updatedUser
  const updatedUserStr = route.query.updatedUser as string
  if (updatedUserStr) {
    try {
      // 解析更新后的用户数据
      const updatedUser = JSON.parse(updatedUserStr)
      
      // 在用户列表中查找匹配的用户并更新其关注状态
      const targetUser = users.value.find(user => user.name === updatedUser.name)
      if (targetUser) {
        targetUser.followed = updatedUser.followed
        // 更新存储的关注状态
        updateFollowedUserInStorage(targetUser.name, updatedUser.followed);
      }
      
      // 在动态列表中也查找并更新相同用户的状态
      const circleUser = circleList.value.find(item => item.name === updatedUser.name)
      if (circleUser) {
        // 这里只是标记，实际项目中可能需要添加followed字段到circleList项目中
        console.log('需要更新动态列表中的用户状态:', updatedUser.name, updatedUser.followed)
      }
      
      // 清除路由参数，避免刷新页面时重复处理
      router.replace({ query: {} })
    } catch (e) {
      console.error('解析用户数据失败', e)
    }
  }
})

// 组件卸载前移除事件监听
onBeforeUnmount(() => {
  window.removeEventListener('scroll', throttledHandleScroll)
  document.removeEventListener('scroll', throttledHandleScroll)
})

// 关注按钮点击事件，user为users.value中的对象
function handleFollow(user: UserType) {
  // 切换关注状态
  user.followed = !user.followed
  // 保存关注状态到localStorage
  updateFollowedUserInStorage(user.name, user.followed);
}

// 更新本地存储中的用户关注状态
function updateFollowedUserInStorage(username: string, isFollowed: boolean) {
  try {
    // 获取已存储的关注用户数据
    const storedDataStr = localStorage.getItem('followedUsers') || '{}';
    const storedData = JSON.parse(storedDataStr);
    
    if (isFollowed) {
      // 找到对应的用户信息
      const user = users.value.find(u => u.name === username);
      if (user) {
        storedData[username] = {
          avatar: user.avatar,
          level: user.level,
          followedAt: new Date().toISOString().slice(0, 10)
        };
      }
    } else {
      delete storedData[username];
    }
    
    localStorage.setItem('followedUsers', JSON.stringify(storedData));
    console.log('已更新本地存储的关注状态:', storedData);
  } catch (error) {
    console.error('保存关注状态失败:', error);
  }
}

// 从本地存储加载用户关注状态
function loadFollowedUsersFromStorage() {
  try {
    const storedDataStr = localStorage.getItem('followedUsers');
    if (storedDataStr) {
      const followedUsers = JSON.parse(storedDataStr);
      
      // 更新用户列表中的关注状态
      users.value.forEach(user => {
        if (followedUsers[user.name]) {
          user.followed = true;
        }
      });
      
      console.log('已从本地存储加载关注状态:', followedUsers);
    }
  } catch (error) {
    console.error('加载关注状态失败:', error);
  }
}

// 从本地存储加载动态列表 - 改进加载机制
async function loadCircleListFromStorage() {
  try {
    const storedDataStr = localStorage.getItem('circleList');
    if (storedDataStr) {
      const storedCircleList = JSON.parse(storedDataStr);
      // 将存储的动态合并到当前动态列表的开头
      if (Array.isArray(storedCircleList) && storedCircleList.length > 0) {
        // 过滤掉可能重复的动态
        const existingIds = circleList.value.map(item => item.id).filter(id => id); // 过滤掉undefined的id
        
        // 处理存储的动态，确保视频URL正确
        const processedItems = await Promise.all(storedCircleList.map(async (item) => {
          // 确保有id
          if (!item.id) {
            item.id = `post_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
          }
          
          // 确保有mediaTypes
          if (!item.mediaTypes && item.images && item.images.length > 0) {
            item.mediaTypes = item.images.map((url: string) => {
              if (typeof url === 'string' && (
                url.endsWith('.mp4') || 
                url.endsWith('.webm') || 
                url.endsWith('.mov') || 
                url.includes('video/mp4') || 
                url.includes('video/webm') ||
                url.includes('#video/')
              )) {
                return 'video';
              }
              return 'image';
            });
          }
          
          // 处理mediaUrls，检查是否是存储在IndexedDB或localStorage中的引用
          if (item.images) {
            const processedUrls = [];
            
            for (let i = 0; i < item.images.length; i++) {
              const url = item.images[i];
              
              if (typeof url === 'string' && url.startsWith('media_') && url.length < 50) {
                // 尝试从IndexedDB加载
                try {
                  const storedMedia = await loadMediaFromIndexedDB(url);
                  if (storedMedia) {
                    console.log('从IndexedDB恢复媒体:', url);
                    processedUrls.push(storedMedia);
                    continue;
                  }
                } catch (error) {
                  console.error('从IndexedDB加载媒体失败:', error);
                }
                
                // 如果IndexedDB加载失败，尝试从localStorage
                const localStorageMedia = localStorage.getItem(url);
                if (localStorageMedia) {
                  console.log('从localStorage恢复媒体:', url);
                  processedUrls.push(localStorageMedia);
                  continue;
                }
                
                // 如果都失败了，保留原始引用
                processedUrls.push(url);
              } else {
                // 不是引用，直接使用原始URL
                processedUrls.push(url);
              }
            }
            
            // 更新媒体URLs
            item.images = processedUrls;
          }
          
          return item;
        }));
        
        // 过滤掉已存在的动态
        const newItems = processedItems.filter(item => !existingIds.includes(item.id));
        
        if (newItems.length > 0) {
          // 将新动态添加到列表开头
          circleList.value = [...newItems, ...circleList.value];
          console.log(`已从本地存储加载 ${newItems.length} 条动态`);
        }
      }
    }
  } catch (error) {
    console.error('加载动态列表失败:', error);
    showToastMessage('加载动态列表失败，请刷新重试', 'error');
  }
}

// 保存动态列表到本地存储 - 改进存储机制
function saveCircleListToStorage() {
  try {
    // 获取当前用户显示名称
    const currentUserName = getUserDisplayName();
    
    // 只保存当前用户发布的动态
    const userPosts = circleList.value.filter(item => item.name === currentUserName);
    if (userPosts.length > 0) {
      // 处理每个动态中的媒体URL
      const processedPosts = userPosts.map(post => {
        // 创建一个新对象，避免修改原对象
        const newPost = { ...post };
        
        // 确保每个帖子都有唯一ID
        if (!newPost.id) {
          newPost.id = `post_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
        }
        
        // 处理媒体类型标记，确保保存
        if (!newPost.mediaTypes) {
          // 如果没有媒体类型标记，根据URL推断
          newPost.mediaTypes = newPost.images.map(url => {
            if (typeof url === 'string' && (
              url.endsWith('.mp4') || 
              url.endsWith('.webm') || 
              url.endsWith('.mov') || 
              url.includes('video/mp4') || 
              url.includes('video/webm') ||
              url.includes('#video/')
            )) {
              return 'video';
            }
            return 'image';
          });
        }
        
        // 为大型media data URLs创建引用，使用IndexedDB而不是localStorage
        if (newPost.images) {
          // 创建一个新的数组来存储处理后的URLs
          const processedUrls: string[] = [];
          
          // 处理每个媒体URL
          newPost.images.forEach((url: string, index: number) => {
            // 如果是大型data URL（超过50KB），创建引用并存储到IndexedDB
            if (typeof url === 'string' && url.startsWith('data:') && url.length > 50000) {
              const mediaKey = `media_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
              const mediaType = newPost.mediaTypes && newPost.mediaTypes[index] ? newPost.mediaTypes[index] : 'unknown';
              
              // 存储到IndexedDB (异步操作，但我们这里简化处理)
              saveMediaToIndexedDB(mediaKey, url, mediaType).then(() => {
                console.log(`已将媒体保存到IndexedDB: ${mediaKey}, 类型: ${mediaType}`);
              }).catch(error => {
                console.error('保存媒体到IndexedDB失败:', error);
              });
              
              // 在帖子中使用引用键
              processedUrls.push(mediaKey);
            } else {
              // 小型媒体直接使用原始URL
              processedUrls.push(url);
            }
          });
          
          // 更新帖子的媒体URLs
          newPost.images = processedUrls;
        }
        
        return newPost;
      });
      
      // 将处理后的帖子保存到localStorage (只保存引用，不保存实际媒体数据)
      localStorage.setItem('circleList', JSON.stringify(processedPosts));
      console.log(`已保存 ${processedPosts.length} 条用户动态到本地存储`);
    }
  } catch (error) {
    console.error('保存动态列表失败:', error);
    // 显示错误提示
    showToastMessage('保存动态失败，媒体文件可能过大', 'error');
  }
}

// 保存媒体到IndexedDB
function saveMediaToIndexedDB(key: string, data: string, type: string): Promise<void> {
  return new Promise((resolve, reject) => {
    try {
      // 打开数据库
      const request = indexedDB.open('FitnessMediaDB', 1);
      
      // 处理数据库升级事件 - 创建对象存储
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        // 如果存储不存在，创建它
        if (!db.objectStoreNames.contains('media')) {
          db.createObjectStore('media', { keyPath: 'id' });
          console.log('已创建media对象存储');
        }
      };
      
      // 处理成功打开数据库
      request.onsuccess = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        
        // 开始事务
        const transaction = db.transaction(['media'], 'readwrite');
        const store = transaction.objectStore('media');
        
        // 存储媒体数据
        const storeRequest = store.put({
          id: key,
          data: data,
          type: type,
          timestamp: Date.now()
        });
        
        // 处理存储成功
        storeRequest.onsuccess = () => {
          resolve();
        };
        
        // 处理存储错误
        storeRequest.onerror = (error) => {
          console.error('保存媒体到IndexedDB时出错:', error);
          reject(error);
        };
        
        // 处理事务完成
        transaction.oncomplete = () => {
          db.close();
        };
      };
      
      // 处理打开数据库错误
      request.onerror = (error) => {
        console.error('打开IndexedDB时出错:', error);
        reject(error);
      };
    } catch (error) {
      console.error('访问IndexedDB时出错:', error);
      reject(error);
    }
  });
}

// 从IndexedDB加载媒体
function loadMediaFromIndexedDB(key: string): Promise<string | null> {
  return new Promise((resolve, reject) => {
    try {
      // 打开数据库
      const request = indexedDB.open('FitnessMediaDB', 1);
      
      // 处理数据库升级事件
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains('media')) {
          db.createObjectStore('media', { keyPath: 'id' });
        }
      };
      
      // 处理成功打开数据库
      request.onsuccess = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        
        // 如果存储不存在，返回null
        if (!db.objectStoreNames.contains('media')) {
          resolve(null);
          return;
        }
        
        // 开始事务
        const transaction = db.transaction(['media'], 'readonly');
        const store = transaction.objectStore('media');
        
        // 获取媒体数据
        const getRequest = store.get(key);
        
        // 处理获取成功
        getRequest.onsuccess = () => {
          const result = getRequest.result;
          if (result) {
            resolve(result.data);
          } else {
            resolve(null);
          }
        };
        
        // 处理获取错误
        getRequest.onerror = (error) => {
          console.error('从IndexedDB获取媒体时出错:', error);
          reject(error);
        };
        
        // 处理事务完成
        transaction.oncomplete = () => {
          db.close();
        };
      };
      
      // 处理打开数据库错误
      request.onerror = (error) => {
        console.error('打开IndexedDB时出错:', error);
        reject(error);
      };
    } catch (error) {
      console.error('访问IndexedDB时出错:', error);
      reject(error);
    }
  });
}

// 将blob URL转换为data URL
function blobToDataURL(blobUrl: string, mediaType: 'video' | 'image' = 'video'): Promise<string> {
  return new Promise((resolve) => {
    try {
      // 如果不是blob URL，直接返回原始URL
      if (!blobUrl.startsWith('blob:')) {
        resolve(blobUrl);
        return;
      }
      
      console.log('开始将blob URL转换为data URL:', blobUrl);
      
      // 从blob URL获取Blob对象
      fetch(blobUrl)
        .then(response => response.blob())
        .then(blob => {
          // 创建FileReader
          const reader = new FileReader();
          
          // 设置onload回调
          reader.onload = () => {
            const dataUrl = reader.result as string;
            
            // 确保data URL有正确的MIME类型
            let processedDataUrl = dataUrl;
            if (mediaType === 'video' && !dataUrl.includes('data:video/')) {
              // 检测blob的实际类型
              const videoType = blob.type || 'video/mp4';
              processedDataUrl = dataUrl
                .replace('data:application/octet-stream', `data:${videoType}`)
                .replace('data:text/plain', `data:${videoType}`);
              
              // 添加视频标记
              if (!processedDataUrl.includes('#video/')) {
                const extension = videoType.split('/')[1] || 'mp4';
                processedDataUrl = processedDataUrl + `#video/${extension}`;
              }
            }
            
            console.log('成功将blob URL转换为data URL');
            // 将data URL保存到localStorage以便页面刷新后仍可访问
            try {
              const mediaKey = `media_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
              localStorage.setItem(mediaKey, processedDataUrl);
              console.log('已保存媒体到localStorage:', mediaKey);
            } catch (storageError) {
              console.warn('媒体可能太大，无法保存到localStorage:', storageError);
            }
            
            resolve(processedDataUrl);
          };
          
          // 设置onerror回调
          reader.onerror = (error) => {
            console.error('将blob URL转换为data URL失败:', error);
            // 如果转换失败，返回原始URL
            resolve(blobUrl);
          };
          
          // 将Blob读取为data URL
          reader.readAsDataURL(blob);
        })
        .catch(error => {
          console.error('获取blob数据失败:', error);
          // 如果获取失败，返回原始URL
          resolve(blobUrl);
        });
    } catch (error) {
      console.error('转换blob URL时出错:', error);
      // 出错时返回原始URL
      resolve(blobUrl);
    }
  });
}

// 处理媒体URL，确保它们在刷新后仍然可用
// 处理媒体URL的函数,用于处理上传的媒体文件URL
async function processMediaURLs(mediaUrls: string[], mediaTypes: ('image' | 'video')[]): Promise<{ urls: string[], types: ('image' | 'video')[] }> {
  try {
    console.log('开始处理媒体URL，确保刷新后可用');
    const processedUrls: string[] = [];
    
    // 逐个处理媒体URL
    for (let i = 0; i < mediaUrls.length; i++) {
      const url = mediaUrls[i];
      const type = mediaTypes[i] || 'image';
      
      // 如果是blob URL，转换为data URL
      if (url.startsWith('blob:')) {
        console.log(`处理第 ${i+1}/${mediaUrls.length} 个媒体，类型: ${type}`);
        const dataUrl = await blobToDataURL(url, type);
        processedUrls.push(dataUrl);
      } else if (type === 'video' && !url.includes('#video/')) {
        // 确保视频URL包含标识符
        const extension = url.split('.').pop()?.toLowerCase() || 'mp4';
        processedUrls.push(`${url}#video/${extension}`);
      } else {
        // 否则直接使用原始URL
        processedUrls.push(url);
      }
    }
    
    console.log('媒体URL处理完成');
    return { urls: processedUrls, types: mediaTypes };
  } catch (error) {
    console.error('处理媒体URL时出错:', error);
    // 出错时返回原始URL
    return { urls: mediaUrls, types: mediaTypes };
  }
}

// 清除我的账号发布的所有动态
function clearMyPosts() {
  try {
    // 获取当前用户显示名称
    const currentUserName = getUserDisplayName();
    
    // 从circleList中移除当前用户发布的动态
    const initialLength = circleList.value.length;
    circleList.value = circleList.value.filter(item => item.name !== currentUserName);
    const removedCount = initialLength - circleList.value.length;
    
    // 清除localStorage中存储的动态
    localStorage.removeItem('circleList');
    
    // 重置分页数据并重新加载
    initData();
    
    // 显示成功提示
    showToastMessage(`已清除${removedCount}条我的动态`, 'success');
    
    console.log(`已清除${removedCount}条${currentUserName}发布的动态`);
    return removedCount;
  } catch (error) {
    console.error('清除动态失败:', error);
    showToastMessage('清除动态失败', 'error');
    return 0;
  }
}

// 跳转到详情页的函数
function goDetail(user: UserType) {
  // 跳转到Detail页面，传递用户数据
  router.push({ 
    name: 'Detail', 
    query: { 
      name: user.name,
      avatar: user.avatar,
      level: user.level.toString(),
      followed: user.followed.toString()
    } 
  })
}

// 控制上拉菜单显示的响应式变量
const showSheet = ref(false)

// 发布表单数据
const postForm = ref({
  title: '', // 标题
  content: '', // 内容
  sportType: '健身训练', // 运动类型，默认值
  distance: '0.00km', // 距离
  time: '00:00:00', // 时间
  calorie: '0千卡', // 消耗
})

// 选择的媒体文件
const selectedMedia = ref<MediaType[]>([])

// 计算属性：过滤出未被移除的媒体
const visibleMedia = computed(() => {
  return selectedMedia.value.filter(media => !media.removed)
})

// 是否正在上传中
const isUploading = ref(false)

// 显示正在上传的提示
const uploadProgress = ref(0)

// 上传错误信息
const uploadError = ref<string | null>(null)

// 文件大小限制（20MB）
const MAX_FILE_SIZE = 20 * 1024 * 1024

// 基础分片大小（2MB）
const BASE_CHUNK_SIZE = 2 * 1024 * 1024;
// 最小分片大小（512KB）
const MIN_CHUNK_SIZE = 512 * 1024;
// 最大分片大小（8MB）
const MAX_CHUNK_SIZE = 8 * 1024 * 1024;
// 当前分片大小 - 可以根据网络状况动态调整
const currentChunkSize = ref(BASE_CHUNK_SIZE);
// 最大并行上传分片数
const MAX_CONCURRENT_CHUNKS = 3;
// 分片上传最大重试次数
const MAX_CHUNK_RETRIES = 3;


// 允许的文件类型
const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
const ALLOWED_VIDEO_TYPES = ['video/mp4', 'video/webm', 'video/quicktime']

// 字数计数
const titleCount = ref(0)

// 上传控制状态 - 增强版
const uploadController = ref<{
  fileId: string | null;
  isPaused: boolean;
  isCancelled: boolean;
  uploadedChunks: Set<number>;
  failedChunks: Map<number, number>; // 分片索引 -> 重试次数
  processingChunks: Set<number>; // 正在处理的分片
  totalChunks: number;
  currentFile: File | null;
  currentFileType: 'image' | 'video' | null;
  md5: string | null;
  uploadStartTime: number | null;
  uploadSpeed: number; // 字节/秒
  estimatedTimeRemaining: number | null; // 秒
  lastNetworkCheckTime: number;
  sessionId: string; // 用于断点续传的会话ID
}>({
  fileId: null,
  isPaused: false,
  isCancelled: false,
  uploadedChunks: new Set<number>(),
  failedChunks: new Map<number, number>(),
  processingChunks: new Set<number>(),
  totalChunks: 0,
  currentFile: null,
  currentFileType: null,
  md5: null,
  uploadStartTime: null,
  uploadSpeed: 0,
  estimatedTimeRemaining: null,
  lastNetworkCheckTime: 0,
  sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
})

// 观察标题长度变化 - 使用防抖处理，减少更新频率
const updateTitleCount = throttle(function() {
  titleCount.value = postForm.value.title.length
}, 100) // 100ms的防抖延迟

// 验证文件类型
function validateFileType(file: File): boolean {
  const isImage = ALLOWED_IMAGE_TYPES.includes(file.type)
  const isVideo = ALLOWED_VIDEO_TYPES.includes(file.type)
  return isImage || isVideo
}

// 获取文件类型
function getFileType(file: File): 'image' | 'video' | null {
  if (ALLOWED_IMAGE_TYPES.includes(file.type)) {
    return 'image'
  } else if (ALLOWED_VIDEO_TYPES.includes(file.type)) {
    return 'video'
  }
  return null
}

// 格式化文件大小
function formatFileSize(bytes: number): string {
  if (bytes < 1024) {
    return bytes + ' B'
  } else if (bytes < 1024 * 1024) {
    return (bytes / 1024).toFixed(2) + ' KB'
  } else {
    return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
  }
}

// 格式化时间（秒）为 分:秒 格式
function formatTime(seconds: number): string {
  if (seconds === null || isNaN(seconds)) return '--:--';
  
  // 如果时间超过1小时，显示为 时:分:秒
  if (seconds > 3600) {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = Math.floor(seconds % 60);
    return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }
  
  // 否则显示为 分:秒
  const minutes = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${minutes}:${secs.toString().padStart(2, '0')}`;
}

// 处理文件选择
function handleFileSelect(event: Event) {
  const fileInput = event.target as HTMLInputElement
  const files = fileInput.files
  
  console.log('文件选择被触发', files)
  
  // 重置错误信息
  uploadError.value = null
  
  // 如果当前有正在上传的文件，提示用户
  if (isUploading.value) {
    uploadError.value = '已有文件正在上传中，请等待上传完成或取消当前上传'
    console.error(uploadError.value)
    
    // 重置input，允许选择相同文件
    try {
      fileInput.value = ''
    } catch (resetError) {
      console.error('重置文件输入框失败', resetError)
    }
    
    return
  }
  
  if (!files || files.length === 0) {
    console.log('没有选择文件')
    return
  }
  
  const file = files[0]
  
  // 立即创建预览URL，不等待上传完成
  const previewFileType = getFileType(file)
  if (previewFileType) {
    // 立即创建文件的URL预览
    const previewUrl = URL.createObjectURL(file)
    
    // 添加到已选媒体中，但标记为正在上传
    const newMedia = {
      file,
      url: previewUrl,
      type: previewFileType,
      size: file.size,
      name: file.name,
      removed: false // 确保新添加的媒体没有被标记为移除
    }
    
    // 确保媒体列表更新触发视图更新
    selectedMedia.value = [...selectedMedia.value, newMedia]
    
    console.log('已创建文件预览', {
      name: file.name,
      type: previewFileType,
      size: formatFileSize(file.size)
    })
  }
  
  // 安全检查
  if (!file) {
    uploadError.value = '文件对象不存在'
    console.error(uploadError.value)
    return
  }
  
  // 文件大小检查
  if (file.size > MAX_FILE_SIZE) {
    uploadError.value = `文件大小超过限制（${formatFileSize(file.size)}，最大允许${formatFileSize(MAX_FILE_SIZE)}）`
    console.error(uploadError.value)
    
    // 如果已经添加了预览，删除它
    const lastMediaIndex = selectedMedia.value.length - 1
    if (lastMediaIndex >= 0 && selectedMedia.value[lastMediaIndex].name === file.name) {
      selectedMedia.value.splice(lastMediaIndex, 1)
    }
    
    // 重置input，允许选择相同文件
    try {
      fileInput.value = ''
    } catch (resetError) {
      console.error('重置文件输入框失败', resetError)
    }
    
    return
  }
  
  // 文件类型检查
  if (!validateFileType(file)) {
    uploadError.value = `不支持的文件类型：${file.type}`
    console.error(uploadError.value)
    
    // 如果已经添加了预览，删除它
    const lastMediaIndex = selectedMedia.value.length - 1
    if (lastMediaIndex >= 0 && selectedMedia.value[lastMediaIndex].name === file.name) {
      selectedMedia.value.splice(lastMediaIndex, 1)
    }
    
    // 重置input，允许选择相同文件
    try {
      fileInput.value = ''
    } catch (resetError) {
      console.error('重置文件输入框失败', resetError)
    }
    
    return
  }
  
      // 文件类型
    const fileType = getFileType(file)
    if (!fileType) {
      uploadError.value = `无法确定文件类型：${file.type}`
      console.error(uploadError.value)
      
      // 如果已经添加了预览，删除它
      const lastMediaIndex = selectedMedia.value.length - 1
      if (lastMediaIndex >= 0 && selectedMedia.value[lastMediaIndex].name === file.name) {
        selectedMedia.value.splice(lastMediaIndex, 1)
      }
      
      return
    }
    
    console.log('开始上传文件', file.name, file.type, formatFileSize(file.size))
  
  // 确保取消任何可能正在进行的上传
  if (currentChunkTimeoutId !== null) {
    console.log(`清除之前可能存在的分片上传计时器 (timeoutId: ${currentChunkTimeoutId})`)
    window.clearTimeout(currentChunkTimeoutId)
    currentChunkTimeoutId = null
  }
  
  // 确保当前没有正在进行的XMLHttpRequest请求
  if (currentXhr !== null) {
    console.log('中止之前可能存在的XMLHttpRequest请求')
    currentXhr.abort()
    currentXhr = null
  }
  
  // 设置上传状态
  isUploading.value = true
  uploadProgress.value = 0
  
  // 重置上传控制器状态
  uploadController.value = {
    fileId: null,
    isPaused: false,
    isCancelled: false,
    uploadedChunks: new Set<number>(),
    failedChunks: new Map<number, number>(),
    processingChunks: new Set<number>(),
    totalChunks: 0,
    currentFile: null,
    currentFileType: null,
    md5: null,
    uploadStartTime: Date.now(),
    uploadSpeed: 0,
    estimatedTimeRemaining: null,
    lastNetworkCheckTime: Date.now(),
    sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
  };
  
  // 计算文件MD5值（用于文件完整性校验）
  calculateFileMD5(file).then(md5 => {
    console.log(`文件MD5: ${md5}`)
    
    // 再次检查上传是否被取消（可能在计算MD5期间被取消）
    if (uploadController.value.isCancelled) {
      console.log('上传已在MD5计算完成后被取消')
      return
    }
    
    // 判断是否需要分片上传（大于5MB的文件使用分片上传）
    if (file.size > 5 * 1024 * 1024) {
      console.log('文件大于5MB，使用分片上传')
      uploadFileWithChunks(file, fileType, md5)
    } else {
      console.log('文件小于5MB，使用普通上传')
      uploadFileNormal(file, fileType, md5)
    }
  
  // 设置上传开始时间
  uploadController.value.uploadStartTime = Date.now()
  uploadController.value.lastNetworkCheckTime = Date.now()
  }).catch(error => {
    uploadError.value = '计算文件MD5失败'
    console.error(uploadError.value, error)
    isUploading.value = false
  })
  
  // 重置input，允许选择相同文件
  try {
    fileInput.value = ''
  } catch (resetError) {
    console.error('重置文件输入框失败', resetError)
  }
}


// 计算文件MD5值的异步函数
async function calculateFileMD5(inputFile: File): Promise<string> {

  return new Promise((resolve) => {
    // 注意：实际项目中，取消下面注释并安装spark-md5依赖
    // 这里我们返回一个模拟的MD5值
    setTimeout(() => {
      // 模拟MD5计算
      const mockMD5 = Array.from(Array(32), () => Math.floor(Math.random() * 16).toString(16)).join('');
      resolve(mockMD5);
      
      /* 实际MD5计算代码
      const blobSlice = File.prototype.slice || (File.prototype as any).mozSlice || (File.prototype as any).webkitSlice;
      const chunkSize = currentChunkSize.value; // 动态分片大小
      const chunks = Math.ceil(file.size / chunkSize);
      let currentChunk = 0;
      const spark = new SparkMD5.ArrayBuffer();
      const fileReader = new FileReader();
      
      fileReader.onload = function(e) {
        if (e.target && e.target.result) {
          spark.append(e.target.result as ArrayBuffer);
          currentChunk++;
          
          if (currentChunk < chunks) {
            loadNext();
          } else {
            const md5 = spark.end();
            resolve(md5);
          }
        } else {
          reject(new Error('文件读取结果为空'));
        }
      };
      
      fileReader.onerror = function(error) {
        reject(error);
      };
      
      function loadNext() {
        const start = currentChunk * chunkSize;
        const end = Math.min(file.size, start + chunkSize);
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
      }
      
      loadNext();
      */
    }, 500);
  });
}

// 普通上传（小文件）
function uploadFileNormal(file: File, fileType: 'image' | 'video', md5: string) {
  // 模拟上传进度
  const simulateUpload = () => {
    const interval = setInterval(() => {
      // 模拟网络波动
      const increment = Math.floor(Math.random() * 15) + 5
      uploadProgress.value = Math.min(uploadProgress.value + increment, 99)
      console.log('上传进度:', uploadProgress.value)
      
      if (uploadProgress.value >= 99) {
        clearInterval(interval)
        
        // 模拟服务器处理时间
        setTimeout(() => {
          uploadProgress.value = 100
          console.log('上传完成，处理文件')
          
          // 上传完成，处理文件预览
          processUploadedFile(file, fileType)
        }, 500)
      }
    }, 200)
  }
  
  // 延迟一点开始模拟上传，避免UI跳跃
  setTimeout(simulateUpload, 100)
}

// 分片上传（大文件）
function uploadFileWithChunks(file: File, fileType: 'image' | 'video', md5: string) {
  console.log('开始分片上传流程')
  
  // 检查是否已经被取消
  if (uploadController.value.isCancelled) {
    console.log('上传已被取消，不会开始分片上传')
    return
  }
  
  // 检查是否已经被暂停
  if (uploadController.value.isPaused) {
    console.log('上传已被暂停，不会开始分片上传')
    return
  }
  
  // 计算分片数量
  const totalChunks = Math.ceil(file.size / currentChunkSize.value)
  
  // 创建文件ID（使用MD5作为文件标识的一部分，确保唯一性）
  const fileId = `${md5}-${Date.now()}`
  
  // 尝试从本地存储恢复上传状态
  const resumeData = tryLoadUploadState(file.name, file.size, md5)
  
  // 初始化上传控制器
  uploadController.value = {
    fileId: resumeData ? resumeData.fileId : fileId,
    isPaused: false,
    isCancelled: false,
    uploadedChunks: resumeData ? new Set<number>(resumeData.uploadedChunks) : new Set<number>(),
    failedChunks: new Map<number, number>(),
    processingChunks: new Set<number>(),
    totalChunks: totalChunks,
    currentFile: file,
    currentFileType: fileType,
    md5: md5,
    uploadStartTime: Date.now(),
    uploadSpeed: 0,
    estimatedTimeRemaining: null,
    lastNetworkCheckTime: Date.now(),
    sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
  }
  
  if (resumeData) {
    console.log(`恢复上传任务: ${resumeData.fileId}，已上传 ${resumeData.uploadedChunks.length}/${totalChunks} 个分片`)
    uploadProgress.value = Math.floor((resumeData.uploadedChunks.length / totalChunks) * 100)
  } else {
    console.log(`创建新上传任务: ${fileId}，文件将被分成 ${totalChunks} 个分片上传，每个分片大小：${formatFileSize(currentChunkSize.value)}`)
  }
  
  // 再次检查是否被取消或暂停（可能在设置过程中被改变）
  if (uploadController.value.isCancelled) {
    console.log('上传在初始化后被取消，不会开始上传分片')
    return
  }
  
  if (uploadController.value.isPaused) {
    console.log('上传在初始化后被暂停，不会开始上传分片')
    return
  }
  
  console.log('分片上传初始化完成，开始并行上传分片')
  // 开始并行上传分片
  uploadMultipleChunks()
}

// 尝试从本地存储加载上传状态
function tryLoadUploadState(fileName: string, fileSize: number, md5: string): { fileId: string, uploadedChunks: number[] } | null {
  try {
    const uploadStateStr = localStorage.getItem('uploadState')
    if (!uploadStateStr) return null
    
    const uploadState = JSON.parse(uploadStateStr)
    
    // 验证是否为同一文件（名称、大小和MD5都匹配）
    if (uploadState.fileName === fileName && 
        uploadState.fileSize === fileSize && 
        uploadState.md5 === md5) {
      return {
        fileId: uploadState.fileId,
        uploadedChunks: uploadState.uploadedChunks
      }
    }
    
    return null
  } catch (error) {
    console.error('加载上传状态失败:', error)
    return null
  }
}

// 保存上传状态到本地存储
function saveUploadState(md5: string) {
  if (!uploadController.value.currentFile) return
  
  try {
    const uploadState = {
      fileId: uploadController.value.fileId,
      fileName: uploadController.value.currentFile.name,
      fileSize: uploadController.value.currentFile.size,
      uploadedChunks: Array.from(uploadController.value.uploadedChunks),
      timestamp: Date.now(),
      md5: md5
    }
    
    localStorage.setItem('uploadState', JSON.stringify(uploadState))
    console.log('保存上传状态:', uploadState)
  } catch (error) {
    console.error('保存上传状态失败:', error)
  }
}

// 清除上传状态
function clearUploadState() {
  try {
    localStorage.removeItem('uploadState')
    console.log('清除上传状态')
  } catch (error) {
    console.error('清除上传状态失败:', error)
  }
}

// 声明一个变量用于存储当前正在上传的分片的计时器ID
let currentChunkTimeoutId: number | null = null;

// 声明一个变量用于存储当前的XMLHttpRequest对象，以便在暂停/取消时调用abort()方法
// 注意：在实际项目中使用，当前模拟环境中未使用
let currentXhr: XMLHttpRequest | null = null;

// 紧急停止所有上传任务的函数 - 完全重写以确保彻底停止
function emergencyStopAllUploads() {
  console.log('紧急停止所有上传任务 - 彻底终止');
  
  // 1. 首先设置全局上传状态为false，阻止任何新的上传尝试
  isUploading.value = false;
  uploadProgress.value = 0;
  
  // 2. 立即清除所有计时器
  if (currentChunkTimeoutId !== null) {
    console.log(`清除当前分片上传计时器 (ID: ${currentChunkTimeoutId})`);
    window.clearTimeout(currentChunkTimeoutId);
    currentChunkTimeoutId = null;
  }
  
  // 3. 中止所有XMLHttpRequest请求
  if (currentXhr !== null) {
    console.log('中止当前XMLHttpRequest请求');
    currentXhr.abort();
    currentXhr = null;
  }
  
  // 4. 清除所有可能的延时任务 - 扩大范围以确保所有计时器被清除
  try {
    // 尝试更彻底的方式清除所有计时器
    const highestId = window.setTimeout(() => {}, 0);
    for (let i = 0; i <= highestId; i++) {
      window.clearTimeout(i);
      window.clearInterval(i);
    }
    console.log(`清除了所有计时器，最高ID: ${highestId}`);
  } catch (error) {
    console.error('清除计时器时出错:', error);
    // 回退到原始方法
    for (let i = 0; i < 10000; i++) {
      window.clearTimeout(i);
      window.clearInterval(i);
    }
  }
  
  // 5. 显式中断任何可能存在的分片上传过程
  if (uploadController.value) {
    console.log('强制重置上传控制器状态');
    
    // 保存当前会话ID以便通知后端
    const sessionId = uploadController.value.sessionId;
    
    // 完全重置上传控制器 - 创建全新对象而不是修改现有对象
    uploadController.value = {
      fileId: null,
      isPaused: true,
      isCancelled: true,
      uploadedChunks: new Set<number>(),
      failedChunks: new Map<number, number>(),
      processingChunks: new Set<number>(),
      totalChunks: 0,
      currentFile: null,
      currentFileType: null,
      md5: null,
      uploadStartTime: null,
      uploadSpeed: 0,
      estimatedTimeRemaining: null,
      lastNetworkCheckTime: 0,
      sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
    };
    
    // 在实际项目中，这里应该发送请求到后端中止所有上传任务
    console.log('通知后端中止所有上传任务:', sessionId);
  }
  
  // 6. 清除上传状态（包括本地存储的状态）
  try {
    localStorage.removeItem('uploadState');
    console.log('清除本地存储的上传状态');
  } catch (error) {
    console.error('清除上传状态失败:', error);
  }
  
  // 7. 清除所有可能的全局变量引用
  try {
    // 确保没有其他引用持有上传状态
    window.onbeforeunload = null;
    console.log('已清除页面卸载事件处理器');
  } catch (error) {
    console.error('清除页面事件处理器失败:', error);
  }
  
  console.log('所有上传任务已彻底停止');
}

// 动态调整分片大小
function adjustChunkSize(uploadSpeed: number) {
  // 如果上传速度大于5MB/s，增加分片大小
  if (uploadSpeed > 5 * 1024 * 1024) {
    const newChunkSize = Math.min(currentChunkSize.value * 1.5, MAX_CHUNK_SIZE);
    if (newChunkSize !== currentChunkSize.value) {
      console.log(`网络良好，增加分片大小: ${formatFileSize(currentChunkSize.value)} -> ${formatFileSize(newChunkSize)}`);
      currentChunkSize.value = newChunkSize;
    }
  } 
  // 如果上传速度小于500KB/s，减小分片大小
  else if (uploadSpeed < 500 * 1024) {
    const newChunkSize = Math.max(currentChunkSize.value * 0.7, MIN_CHUNK_SIZE);
    if (newChunkSize !== currentChunkSize.value) {
      console.log(`网络不佳，减小分片大小: ${formatFileSize(currentChunkSize.value)} -> ${formatFileSize(newChunkSize)}`);
      currentChunkSize.value = newChunkSize;
    }
  }
}

// 并行上传多个分片
function uploadMultipleChunks() {
  // 如果上传已取消或暂停，则不处理
  if (uploadController.value.isCancelled || uploadController.value.isPaused || !isUploading.value || !uploadController.value.currentFile) {
    console.log('上传已取消、暂停或上传状态无效，不会开始并行上传');
    return;
  }
  
  const file = uploadController.value.currentFile;
  if (!file) {
    console.error('没有当前上传文件');
    return;
  }
  
  // 查找所有可上传的分片
  const pendingChunks: number[] = [];
  for (let i = 0; i < uploadController.value.totalChunks; i++) {
    // 如果分片未上传且未在处理中，则添加到待上传列表
    if (!uploadController.value.uploadedChunks.has(i) && 
        !uploadController.value.processingChunks.has(i)) {
      pendingChunks.push(i);
      
      // 如果已达到最大并行数，则停止添加
      if (pendingChunks.length >= MAX_CONCURRENT_CHUNKS) {
        break;
      }
    }
  }
  
  // 如果没有待上传分片，检查是否所有分片都已上传
  if (pendingChunks.length === 0) {
    if (uploadController.value.uploadedChunks.size === uploadController.value.totalChunks) {
      console.log('所有分片已上传，通知服务器合并分片');
      // 确保进度显示为接近完成
      uploadProgress.value = 99;
      
      // 模拟服务器合并分片的过程
      setTimeout(() => {
        // 再次检查是否被取消或暂停
        if (uploadController.value.isCancelled || uploadController.value.isPaused || !isUploading.value || !uploadController.value.currentFile) {
          console.log('合并分片过程被取消、暂停或上传状态无效');
          
          // 确保清理所有状态
          isUploading.value = false;
          uploadProgress.value = 0;
          
          // 清除本地存储的上传状态
          try {
            localStorage.removeItem('uploadState');
            console.log('已清除本地存储的上传状态');
          } catch (error) {
            console.error('清除上传状态失败:', error);
          }
          
          return;
        }
        
        // 检查文件是否已被标记为移除
        const currentFileName = uploadController.value.currentFile.name;
        const isFileRemoved = selectedMedia.value.some(media => 
          (media.file && media.file.name === currentFileName && media.removed === true) ||
          (media.name === currentFileName && media.removed === true)
        );
        
        if (isFileRemoved) {
          console.log(`文件 ${currentFileName} 已被标记为移除，取消合并分片`);
          
          // 确保清理所有状态
          isUploading.value = false;
          uploadProgress.value = 0;
          
          // 清除本地存储的上传状态
          try {
            localStorage.removeItem('uploadState');
            console.log('已清除本地存储的上传状态');
          } catch (error) {
            console.error('清除上传状态失败:', error);
          }
          
          return;
        }
        
        console.log('服务器合并分片完成');
        // 设置进度为100%
        uploadProgress.value = 100;
        
        // 处理上传完成的文件
        processUploadedFile(file, uploadController.value.currentFileType!);
        // 清除上传状态
        clearUploadState();
        
        // 重置上传控制器
        uploadController.value = {
          fileId: null,
          isPaused: false,
          isCancelled: false,
          uploadedChunks: new Set<number>(),
          failedChunks: new Map<number, number>(),
          processingChunks: new Set<number>(),
          totalChunks: 0,
          currentFile: null,
          currentFileType: null,
          md5: null,
          uploadStartTime: null,
          uploadSpeed: 0,
          estimatedTimeRemaining: null,
          lastNetworkCheckTime: 0,
          sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
        };
      }, 1000);
    } else {
      // 如果还有分片但当前没有待上传的，可能是因为它们都在处理中
      // 等待一会儿再检查
      console.log('当前没有可上传的分片，但上传尚未完成，等待处理中的分片...');
      setTimeout(() => {
        if (!uploadController.value.isPaused && !uploadController.value.isCancelled && isUploading.value && uploadController.value.currentFile) {
          uploadMultipleChunks();
        }
      }, 500);
    }
    return;
  }
  
  // 并行上传所有待上传分片
  console.log(`开始并行上传 ${pendingChunks.length} 个分片`);
  pendingChunks.forEach(chunkIndex => {
    uploadChunk(chunkIndex);
  });
}

// 上传单个分片
function uploadChunk(chunkIndex: number) {
  // 如果上传已取消或暂停，则不处理
  if (uploadController.value.isCancelled || uploadController.value.isPaused || !isUploading.value || !uploadController.value.currentFile) {
    console.log(`分片 ${chunkIndex + 1} 上传已取消、暂停或上传状态无效`);
    return;
  }
  
  const file = uploadController.value.currentFile;
  if (!file) {
    console.error('没有当前上传文件');
    return;
  }
  
  // 如果分片已经上传过，跳过
  if (uploadController.value.uploadedChunks.has(chunkIndex)) {
    console.log(`分片 ${chunkIndex + 1} 已上传过，跳过`);
    // 继续处理其他分片
    uploadMultipleChunks();
    return;
  }
  
  // 标记分片为处理中
  uploadController.value.processingChunks.add(chunkIndex);
  
  // 计算分片范围
  const start = chunkIndex * currentChunkSize.value;
  const end = Math.min(file.size, start + currentChunkSize.value);
  
  // 从文件中切出分片
  const chunk = file.slice(start, end);
  
  console.log(`上传分片 ${chunkIndex + 1}/${uploadController.value.totalChunks}，大小：${formatFileSize(chunk.size)}`);
  
  // 计算进度增量 - 确保恢复上传后有明显的进度变化
  const progressIncrement = 100 / uploadController.value.totalChunks;
  
  // 模拟上传延迟 - 恢复上传后加快速度以提供更好的用户体验
  const isPaused = uploadController.value.isPaused;
  const delay = isPaused ? 300 + Math.random() * 700 : 200 + Math.random() * 400;
  console.log(`开始上传分片 ${chunkIndex + 1}，预计用时：${delay.toFixed(0)}ms`);
  
  setTimeout(() => {
    try {
      // 再次检查上传状态
      if (uploadController.value.isCancelled || uploadController.value.isPaused || !isUploading.value || !uploadController.value.currentFile) {
        console.log(`分片 ${chunkIndex + 1} 上传已在延迟后被取消、暂停或上传状态无效`);
        // 移除处理中标记
        uploadController.value.processingChunks.delete(chunkIndex);
        return;
      }
      
      // 模拟上传成功
      uploadController.value.uploadedChunks.add(chunkIndex);
      // 移除处理中标记
      uploadController.value.processingChunks.delete(chunkIndex);
      // 移除失败记录（如果有）
      uploadController.value.failedChunks.delete(chunkIndex);
      
      // 更新上传进度 - 使用更精确的计算方式
      const exactProgress = (uploadController.value.uploadedChunks.size / uploadController.value.totalChunks) * 100;
      // 确保进度不会超过99%（留1%给合并阶段）
      uploadProgress.value = Math.min(Math.floor(exactProgress), 99);
      console.log(`分片 ${chunkIndex + 1} 上传完成，总进度：${uploadProgress.value}%，精确进度：${exactProgress.toFixed(2)}%`);
      
      // 更新上传速度和预计剩余时间
      if (uploadController.value.uploadStartTime) {
        const now = Date.now();
        const elapsedTime = (now - uploadController.value.uploadStartTime) / 1000; // 秒
        if (elapsedTime > 0) {
          // 估算上传速度（字节/秒）
          const totalBytes = file.size;
          const uploadedBytes = (uploadController.value.uploadedChunks.size / uploadController.value.totalChunks) * totalBytes;
          const bytesPerSecond = uploadedBytes / elapsedTime;
          
          // 更新上传速度（使用移动平均值）
          uploadController.value.uploadSpeed = uploadController.value.uploadSpeed * 0.7 + bytesPerSecond * 0.3;
          
          // 估算剩余时间
          const remainingBytes = totalBytes - uploadedBytes;
          if (uploadController.value.uploadSpeed > 0) {
            uploadController.value.estimatedTimeRemaining = remainingBytes / uploadController.value.uploadSpeed;
          }
        }
      }
      
      // 每上传5个分片保存一次状态
      if (uploadController.value.uploadedChunks.size % 5 === 0 && uploadController.value.md5) {
        saveUploadState(uploadController.value.md5);
      }
      
      // 继续上传其他分片
      uploadMultipleChunks();
    } catch (error) {
      console.error(`分片 ${chunkIndex + 1} 上传出错:`, error);
      
      // 记录失败次数
      const retryCount = (uploadController.value.failedChunks.get(chunkIndex) || 0) + 1;
      uploadController.value.failedChunks.set(chunkIndex, retryCount);
      
      // 移除处理中标记
      uploadController.value.processingChunks.delete(chunkIndex);
      
      // 如果未超过最大重试次数，稍后重试
      if (retryCount <= MAX_CHUNK_RETRIES) {
        console.log(`分片 ${chunkIndex + 1} 将在 ${retryCount * 2}秒后重试 (${retryCount}/${MAX_CHUNK_RETRIES})`);
        setTimeout(() => {
          // 再次检查上传状态
          if (!uploadController.value.isCancelled && !uploadController.value.isPaused) {
            console.log(`重试上传分片 ${chunkIndex + 1}`);
            uploadChunk(chunkIndex);
          }
        }, retryCount * 2000);
      } else {
        console.error(`分片 ${chunkIndex + 1} 上传失败，已达到最大重试次数`);
        // 可以在这里添加失败处理逻辑
      }
    }
  }, delay);
}

// 上传下一个分片 - 旧版本，保留以兼容现有代码
function uploadNextChunk() {
  console.log('uploadNextChunk - 开始检查上传状态')
  
  try {
    // 立即获取最新的状态值
    const isCancelled = uploadController.value.isCancelled
    const isPaused = uploadController.value.isPaused
    
  // 如果上传已取消，则退出
    if (isCancelled) {
      console.log('上传已取消 - 不会上传新分片')
    isUploading.value = false
    clearUploadState()
    return
  }
  
  // 如果上传已暂停，则退出
    if (isPaused) {
      console.log('上传已暂停 - 不会上传新分片')
    // 保存上传状态，以便稍后恢复
    if (uploadController.value.md5) {
      saveUploadState(uploadController.value.md5)
        console.log(`已保存上传状态 (md5: ${uploadController.value.md5.substring(0, 8)}...)`)
    }
      return
    }
  } catch (error) {
    console.error('检查上传状态时出错:', error)
    return
  }
  
  // 获取当前文件和类型
  const file = uploadController.value.currentFile
  const fileType = uploadController.value.currentFileType
  
  if (!file || !fileType) {
    console.error('当前没有上传任务')
    isUploading.value = false
    return
  }
  
  console.log('uploadNextChunk - 状态检查通过，准备上传下一个分片')
  
  // 查找下一个需要上传的分片
  let nextChunkIndex = -1
  for (let i = 0; i < uploadController.value.totalChunks; i++) {
    if (!uploadController.value.uploadedChunks.has(i)) {
      nextChunkIndex = i
      break
    }
  }
  
  // 如果所有分片已上传，则完成上传
  if (nextChunkIndex === -1) {
    console.log('所有分片已上传，通知服务器合并分片')
    
    // 模拟服务器合并分片的过程
    currentChunkTimeoutId = window.setTimeout(() => {
      // 再次检查是否被取消或暂停
      if (uploadController.value.isCancelled) {
        console.log('合并分片过程被取消')
        currentChunkTimeoutId = null
        return
      }
      
      if (uploadController.value.isPaused) {
        console.log('合并分片过程被暂停')
        currentChunkTimeoutId = null
        return
      }
      
      currentChunkTimeoutId = null;
      console.log('服务器合并分片完成')
      
      // 处理上传完成的文件
      processUploadedFile(file, fileType)
      
      // 清除上传状态
      clearUploadState()
      
      // 重置上传控制器
      uploadController.value = {
        fileId: null,
        isPaused: false,
        isCancelled: false,
        uploadedChunks: new Set<number>(),
        failedChunks: new Map<number, number>(),
        processingChunks: new Set<number>(),
        totalChunks: 0,
        currentFile: null,
        currentFileType: null,
        md5: null,
        uploadStartTime: null,
        uploadSpeed: 0,
        estimatedTimeRemaining: null,
        lastNetworkCheckTime: 0,
        sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
      }
    }, 1000) as unknown as number;
    
    return
  }
  
  // 在开始上传新分片前，再次检查是否被取消或暂停
  if (uploadController.value.isCancelled) {
    console.log('准备上传新分片时检测到取消状态，停止上传')
    return
  }
  
  if (uploadController.value.isPaused) {
    console.log('准备上传新分片时检测到暂停状态，停止上传')
    return
  }
  
  // 计算当前分片的起始位置和结束位置
  const start = nextChunkIndex * currentChunkSize.value
  const end = Math.min(file.size, start + currentChunkSize.value)
  
  // 从文件中切出分片
  const chunk = file.slice(start, end)
  
  console.log(`上传分片 ${nextChunkIndex + 1}/${uploadController.value.totalChunks}，大小：${formatFileSize(chunk.size)}`)
  
  /* 在实际项目中，应该使用XMLHttpRequest实现可取消的上传，例如：
  const xhr = new XMLHttpRequest();
  // 将xhr对象存储在一个全局变量中，以便在暂停/取消时可以调用xhr.abort()
  currentXhr = xhr;
  
  xhr.open('POST', 'your-upload-url');
  xhr.onload = function() {
    if (xhr.status === 200) {
      // 上传成功，处理响应
      uploadController.value.uploadedChunks.add(currentChunkIndex);
      // 更新进度
      uploadProgress.value = Math.floor((uploadController.value.uploadedChunks.size / uploadController.value.totalChunks) * 100);
      // 检查是否暂停或取消
      if (!uploadController.value.isPaused && !uploadController.value.isCancelled) {
        uploadNextChunk(); // 继续上传下一个分片
      }
    }
  };
  
  // 添加进度监听，用于计算上传速度
  xhr.upload.onprogress = function(e) {
    if (e.lengthComputable) {
      // 计算当前分片的上传速度
      const now = Date.now();
      const elapsedTime = (now - uploadController.value.lastNetworkCheckTime) / 1000; // 秒
      if (elapsedTime > 0) {
        const bytesPerSecond = e.loaded / elapsedTime;
        // 更新上传速度（使用移动平均值）
        uploadController.value.uploadSpeed = 
          uploadController.value.uploadSpeed * 0.7 + bytesPerSecond * 0.3;
        
        // 估算剩余时间
        const totalBytes = file.size;
        const uploadedBytes = currentChunkIndex * currentChunkSize.value + e.loaded;
        const remainingBytes = totalBytes - uploadedBytes;
        
        if (uploadController.value.uploadSpeed > 0) {
          uploadController.value.estimatedTimeRemaining = 
            remainingBytes / uploadController.value.uploadSpeed;
        }
        
        // 动态调整分片大小
        adjustChunkSize(uploadController.value.uploadSpeed);
        
        // 更新最后检查时间
        uploadController.value.lastNetworkCheckTime = now;
      }
    }
  };
  
  // 暂停和取消函数中应该调用：
  // if (currentXhr) currentXhr.abort();
  
  // 创建FormData对象
  const formData = new FormData();
  formData.append('file', chunk);
  formData.append('chunkIndex', String(currentChunkIndex));
  formData.append('totalChunks', String(uploadController.value.totalChunks));
  formData.append('fileId', uploadController.value.fileId || '');
  formData.append('sessionId', uploadController.value.sessionId);
  
  // 发送请求
  xhr.send(formData);
  */
  
  // 这里我们使用 setTimeout 模拟网络请求
  const delay = 300 + Math.random() * 700; // 模拟网络延迟 300-1000ms
  console.log(`开始上传分片 ${nextChunkIndex + 1}，预计用时：${delay.toFixed(0)}ms`);
  
  // 存储当前分片索引，用于日志记录
  const currentChunkIndex = nextChunkIndex;
  
  // 将当前分片索引存储在闭包外部，以便在暂停/取消时可以访问
  const chunkIndexForLog = currentChunkIndex;
  
  // 输出当前状态
  logUploadStatus(`准备上传分片 ${chunkIndexForLog + 1}`);
  
  // 立即再次检查上传控制器的状态 - 这是关键点，确保使用最新的状态值
  const isPaused = uploadController.value.isPaused;
  const isCancelled = uploadController.value.isCancelled;
  
  // 检查上传是否已暂停或取消 - 在创建计时器前检查
  if (isPaused) {
    console.log(`分片 ${chunkIndexForLog + 1} 上传已在计时器创建前被暂停`);
    return; // 如果已暂停，不创建计时器
  }
  
  if (isCancelled) {
    console.log(`分片 ${chunkIndexForLog + 1} 上传已在计时器创建前被取消`);
    return; // 如果已取消，不创建计时器
  }
  
  console.log(`开始创建分片 ${chunkIndexForLog + 1} 的上传计时器`);
  
  // 记录当前计时器ID，以便在回调中使用
  const timeoutIdForLog = currentChunkTimeoutId;
  
  // 存储当前分片的上传计时器ID，以便在暂停时可以取消
  currentChunkTimeoutId = window.setTimeout(() => {
    try {
      // 清除当前计时器ID
      currentChunkTimeoutId = null;
      
      // 再次获取最新的状态值
      const isCancelled = uploadController.value.isCancelled;
      const isPaused = uploadController.value.isPaused;
      
    // 如果上传已取消，则不处理响应
      if (isCancelled) {
        console.log(`分片 ${chunkIndexForLog + 1} 上传已取消 (timeoutId: ${timeoutIdForLog})`)
        return
      }
      
      // 再次检查是否暂停，以确保在异步操作中也能响应暂停
      if (isPaused) {
        console.log(`分片 ${chunkIndexForLog + 1} 上传已暂停 (timeoutId: ${timeoutIdForLog})`)
        return
      }
    } catch (error) {
      console.error('计时器回调中检查状态出错:', error)
      return
    }
    
    // 模拟上传成功
    uploadController.value.uploadedChunks.add(chunkIndexForLog)
    
    // 更新上传进度
    uploadProgress.value = Math.floor((uploadController.value.uploadedChunks.size / uploadController.value.totalChunks) * 100)
    console.log(`分片 ${chunkIndexForLog + 1} 上传完成，总进度：${uploadProgress.value}% (timeoutId: ${timeoutIdForLog})`)
    
    // 每上传5个分片保存一次状态
    if (uploadController.value.uploadedChunks.size % 5 === 0 && uploadController.value.md5) {
      saveUploadState(uploadController.value.md5)
    }
    
    // 继续上传下一个分片前，再次检查是否被取消或暂停
    if (uploadController.value.isCancelled) {
      console.log('准备上传下一个分片时检测到取消状态，停止上传')
      return
    }
    
    if (uploadController.value.isPaused) {
      console.log('准备上传下一个分片时检测到暂停状态，停止上传')
      return
    }
    
    // 继续上传下一个分片
    uploadNextChunk()
  }, delay) as unknown as number;
  
  console.log(`创建分片 ${chunkIndexForLog + 1} 上传计时器 ID: ${currentChunkTimeoutId}`);
}

// 暂停上传
function pauseUpload() {
  if (isUploading.value && !uploadController.value.isPaused) {
    console.log('暂停上传 - 开始暂停流程')
    
    try {
      // 首先设置暂停标志，确保新的分片不会被创建
    uploadController.value.isPaused = true
      // 确保取消标志为false
      uploadController.value.isCancelled = false
      
      // 强制同步更新状态
      uploadController.value = { ...uploadController.value }
      
      // 紧急停止所有上传任务
      emergencyStopAllUploads()
      
      // 取消所有正在进行的分片上传
      uploadController.value.processingChunks.forEach(chunkIndex => {
        console.log(`强制取消分片 ${chunkIndex + 1} 的上传`);
      });
      
      // 清空正在处理的分片集合
      uploadController.value.processingChunks.clear();
      
      // 通知后端暂停上传（实际项目中实现）
      console.log('通知后端暂停上传任务:', uploadController.value.sessionId);
      
    // 保存上传状态，以便稍后恢复
    if (uploadController.value.md5) {
      saveUploadState(uploadController.value.md5)
        console.log('已保存上传状态，可在恢复时使用')
      }
      
      // 确保媒体项不被移除
      if (uploadController.value.currentFile) {
        const currentFileName = uploadController.value.currentFile.name;
        // 查找当前上传的媒体项
        const mediaIndex = selectedMedia.value.findIndex(media => 
          media.file && media.file.name === currentFileName
        );
        
        if (mediaIndex !== -1) {
          // 确保媒体没有被标记为已移除
          selectedMedia.value[mediaIndex].removed = false;
          console.log(`确保暂停后媒体项 ${currentFileName} 不被移除`);
        }
      }
      
      // 显示暂停提示
      showToastMessage('上传已暂停，您可以稍后继续上传', 'warning');
      console.log('暂停上传 - 暂停流程完成')
      
      // 输出当前状态
      logUploadStatus('暂停后');
    } catch (error) {
      console.error('暂停上传时出错:', error)
    }
  }
}

// 调试函数：输出当前上传状态
function logUploadStatus(context: string) {
  console.log(`===== 上传状态 [${context}] =====`);
  console.log(`isUploading: ${isUploading.value}`);
  console.log(`uploadProgress: ${uploadProgress.value}%`);
  console.log(`currentChunkTimeoutId: ${currentChunkTimeoutId}`);
  console.log(`currentXhr: ${currentXhr ? '存在' : '不存在'}`);
  
  if (uploadController.value) {
    console.log('uploadController:');
    console.log(`  isPaused: ${uploadController.value.isPaused}`);
    console.log(`  isCancelled: ${uploadController.value.isCancelled}`);
    console.log(`  fileId: ${uploadController.value.fileId}`);
    console.log(`  totalChunks: ${uploadController.value.totalChunks}`);
    console.log(`  uploadedChunks: ${uploadController.value.uploadedChunks.size}/${uploadController.value.totalChunks}`);
    
    if (uploadController.value.currentFile) {
      console.log(`  currentFile: ${uploadController.value.currentFile.name} (${formatFileSize(uploadController.value.currentFile.size)})`);
    } else {
      console.log('  currentFile: 无');
    }
  } else {
    console.log('uploadController: 未初始化');
  }
  console.log('========================');
}

// 恢复上传
function resumeUpload() {
  if (isUploading.value && uploadController.value.isPaused) {
    console.log('恢复上传 - 开始恢复流程')
    
    // 输出恢复前的状态
    logUploadStatus('恢复前');
    
    // 先停止所有可能正在进行的上传任务
    emergencyStopAllUploads()
    
    // 重置暂停和取消标志
    uploadController.value.isPaused = false
    uploadController.value.isCancelled = false
    
    // 重置上传开始时间，以便正确计算上传速度
    uploadController.value.uploadStartTime = Date.now();
    uploadController.value.lastNetworkCheckTime = Date.now();
    
    // 强制同步更新状态
    uploadController.value = { ...uploadController.value }
    
    // 确保媒体项存在并可见
    if (uploadController.value.currentFile) {
      const currentFileName = uploadController.value.currentFile.name;
      // 查找当前上传的媒体项
      const mediaIndex = selectedMedia.value.findIndex(media => 
        media.file && media.file.name === currentFileName
      );
      
      if (mediaIndex !== -1) {
        // 确保媒体没有被标记为已移除
        selectedMedia.value[mediaIndex].removed = false;
        console.log(`确保恢复上传时媒体项 ${currentFileName} 可见`);
      } else {
        // 如果找不到媒体项，可能需要重新创建
        console.log(`未找到媒体项 ${currentFileName}，可能需要重新创建预览`);
        
        // 如果有当前文件，尝试重新创建预览
        if (uploadController.value.currentFile && uploadController.value.currentFileType) {
          const file = uploadController.value.currentFile;
          const fileType = uploadController.value.currentFileType;
          
          // 创建新的预览URL
          const previewUrl = URL.createObjectURL(file);
          
          // 添加到媒体列表
          selectedMedia.value.push({
            file,
            url: previewUrl,
            type: fileType,
            size: file.size,
            name: file.name,
            removed: false
          });
          
          console.log(`已为 ${file.name} 重新创建预览`);
        }
      }
    }
    
    // 显示恢复提示
    showToastMessage('已恢复上传', 'info');
    
    console.log('恢复上传 - 准备开始上传')
    
    // 使用模拟进度更新来显示上传正在继续
    const currentProgress = uploadProgress.value;
    if (currentProgress < 99) {
      // 立即显示一点进度变化，让用户知道上传已经恢复
      uploadProgress.value = Math.min(currentProgress + 2, 99);
      console.log(`恢复上传后立即更新进度: ${uploadProgress.value}%`);
      
      // 再延迟一点时间后再次更新进度，给用户更明显的反馈
      setTimeout(() => {
        if (!uploadController.value.isPaused && !uploadController.value.isCancelled) {
          uploadProgress.value = Math.min(uploadProgress.value + 1, 99);
          console.log(`恢复上传后再次更新进度: ${uploadProgress.value}%`);
        }
      }, 300);
    }
    
    // 使用并行上传替代单个分片上传
    uploadMultipleChunks();
    
    // 输出恢复后的状态
    logUploadStatus('恢复后');
  }
}

// 取消上传并通知后端删除已上传分片
function cancelUpload() {
  if (isUploading.value) {
    console.log('取消上传 - 开始取消流程')
    
    try {
      // 输出取消前的状态
      logUploadStatus('取消前');
      
      // 获取当前文件信息（在修改状态前）
      const currentFile = uploadController.value.currentFile ? { ...uploadController.value.currentFile } : null;
      const currentFileType = uploadController.value.currentFileType;
      const currentFileName = currentFile ? currentFile.name : '';
      const fileId = uploadController.value.fileId;
      const sessionId = uploadController.value.sessionId;
      
      // 首先设置取消标志，确保新的分片不会被创建
      uploadController.value.isCancelled = true;
      // 同时设置暂停标志，双重保险
      uploadController.value.isPaused = true;
      
      // 强制同步更新状态
      uploadController.value = { ...uploadController.value };
      
      // 立即更新上传状态
      isUploading.value = false;
      uploadProgress.value = 0;
      
      // 紧急停止所有上传任务
      emergencyStopAllUploads();
      
      // 通知后端删除已上传的分片
      if (fileId || sessionId) {
        console.log(`通知后端删除已上传分片: fileId=${fileId}, sessionId=${sessionId}`);
        
        // 在实际项目中，这里应该发送请求到后端删除分片
        // 例如:
        /*
        fetch('/api/upload/cancel', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            fileId: fileId,
            sessionId: sessionId,
            fileName: currentFileName
          })
        })
        .then(response => response.json())
        .then(data => {
          console.log('后端删除分片响应:', data);
        })
        .catch(error => {
          console.error('通知后端删除分片失败:', error);
        });
        */
        
        // 模拟后端响应
        console.log('后端已删除所有已上传分片');
      }
      
      // 自动从页面中移除所有相关媒体
      if (currentFile) {
        console.log('准备移除文件:', currentFileName);
        
        // 先标记所有媒体为已移除
        selectedMedia.value.forEach((media) => {
          media.removed = true;
        });
        
        // 强制更新视图
        selectedMedia.value = [...selectedMedia.value];
        console.log('已标记所有媒体为已移除');
        
        // 延迟后再释放资源并清空数组
        setTimeout(() => {
          // 释放所有URL资源
          selectedMedia.value.forEach((media) => {
            if (media.url) {
              try {
                URL.revokeObjectURL(media.url);
                console.log(`已释放媒体URL: ${media.name}`);
              } catch (e) {
                console.error('释放URL时出错:', e);
              }
            }
          });
          
          // 清空数组
          const mediaCount = selectedMedia.value.length;
          selectedMedia.value = [];
          console.log(`已清空所有媒体，移除了 ${mediaCount} 个媒体项`);
          
          // 确保视图立即更新
          nextTick(() => {
            console.log('DOM已更新，媒体列表现在为空');
          });
        }, 300);
        
        // 清空已上传的分片记录
        const chunkCount = uploadController.value.uploadedChunks.size;
        console.log(`清除所有已上传分片数据 (${chunkCount} 个分片)`);
        uploadController.value.uploadedChunks.clear();
        uploadController.value.processingChunks.clear();
        uploadController.value.failedChunks.clear();
        
        // 清空上传控制器状态
        uploadController.value.fileId = null;
        uploadController.value.currentFile = null;
        uploadController.value.currentFileType = null;
        uploadController.value.totalChunks = 0;
        uploadController.value.md5 = null;
        
        // 显示Toast提示
        showToastMessage(`已取消上传并删除所有媒体`, 'warning');
      }
      
      // 清除上传状态（包括本地存储的状态）
      clearUploadState();
      
      console.log('已成功取消上传并清除所有分片数据和媒体');
      console.log('取消上传 - 取消流程完成');
      
      // 输出取消后的状态
      logUploadStatus('取消后');
    } catch (error) {
      console.error('取消上传时出错:', error);
      // 确保即使出错，也会重置上传状态
      isUploading.value = false;
      uploadProgress.value = 0;
      currentChunkTimeoutId = null;
      currentXhr = null;
      
      // 尝试紧急清理所有媒体
      try {
        // 清空所有媒体
        selectedMedia.value.forEach(media => {
          if (media.url) {
            try {
              URL.revokeObjectURL(media.url);
            } catch (e) {}
          }
        });
        
        // 直接清空媒体数组
        selectedMedia.value = [];
        
        // 清空上传控制器
        if (uploadController.value) {
          uploadController.value.currentFile = null;
        }
        
        showToastMessage('已紧急取消上传并清空所有媒体', 'error');
      } catch (cleanupError) {
        console.error('紧急清理媒体列表时出错:', cleanupError);
      }
    }
  }
}

// 重试上传
function retryUpload() {
  if (uploadController.value.currentFile && uploadController.value.currentFileType) {
    console.log('重试上传')
    isUploading.value = true
    uploadProgress.value = 0
    uploadController.value.isPaused = false
    uploadController.value.isCancelled = false
    uploadNextChunk()
  }
}

// 处理上传完成的文件 - 添加视频类型标记
function processUploadedFile(file: File, fileType: 'image' | 'video') {
  try {
    console.log('文件上传完成，处理预览状态')
    console.log(`文件类型: ${fileType}, 文件名: ${file.name}, 大小: ${formatFileSize(file.size)}`)
    
    // 先检查全局上传状态，如果已取消则不处理
    if (!isUploading.value || uploadController.value.isCancelled) {
      console.log('上传已被取消或暂停，不处理上传完成事件')
      isUploading.value = false
      return
    }
    
    // 检查是否被标记为已移除，如果是，则不处理
    const isRemoved = selectedMedia.value.some(media => 
      (media.name === file.name && media.size === file.size && media.removed === true) ||
      (media.file && media.file.name === file.name && media.removed === true)
    )
    
    if (isRemoved) {
      console.log('文件已被标记为移除，不处理上传完成事件')
      isUploading.value = false
      
      // 清除本地存储的上传状态
      try {
        localStorage.removeItem('uploadState')
        console.log('已清除本地存储的上传状态')
      } catch (error) {
        console.error('清除上传状态失败:', error)
      }
      
      return
    }
    
    // 查找是否已存在此文件的预览
    const existingMediaIndex = selectedMedia.value.findIndex(media => 
      media.name === file.name && media.size === file.size
    )
    
    if (existingMediaIndex !== -1) {
      // 文件已经存在于预览中，更新状态即可
      console.log('找到现有的预览，更新状态')
      
      // 确保视频文件有正确的类型标记
      if (fileType === 'video' && selectedMedia.value[existingMediaIndex].url) {
        const url = selectedMedia.value[existingMediaIndex].url
        const extension = file.name.split('.').pop()?.toLowerCase() || 'mp4'
        
        if (!url.includes('#video/')) {
          selectedMedia.value[existingMediaIndex].url = url + '#video/' + extension
          console.log('已为现有视频添加类型标记')
        }
      }
    } else {
      // 如果预览不存在（极少数情况），创建新的预览
      console.log('未找到现有预览，创建新预览')
      
      const fileReader = new FileReader()
      
      fileReader.onload = (e) => {
        try {
          if (e.target && e.target.result) {
            let url = e.target.result as string
            console.log('文件读取完成，生成预览URL')
            
            // 对于视频文件，添加类型标记以便在刷新后正确识别
            if (fileType === 'video') {
              // 获取文件扩展名
              const extension = file.name.split('.').pop()?.toLowerCase() || 'mp4'
              // 如果URL不包含视频类型标记，添加一个
              if (!url.includes('#video/')) {
                url = url + '#video/' + extension
              }
              
              // 如果是data URL但没有正确的视频MIME类型
              if (url.startsWith('data:') && !url.includes('data:video/')) {
                url = url.replace('data:application/octet-stream', `data:video/${extension}`)
                     .replace('data:text/plain', `data:video/${extension}`);
              }
            }
            
            selectedMedia.value.push({
              file,
              url,
              type: fileType,
              size: file.size,
              name: file.name,
              removed: false // 确保处理完成的文件不会被标记为已移除
            })
            
            console.log('媒体添加成功', {
              name: file.name,
              type: fileType,
              size: formatFileSize(file.size)
            })
          } else {
            uploadError.value = '文件读取结果为空'
            console.error(uploadError.value)
          }
        } catch (readError) {
          uploadError.value = '处理文件预览时出错'
          console.error(uploadError.value, readError)
        } finally {
          isUploading.value = false
        }
      }
      
      fileReader.onerror = (error) => {
        uploadError.value = '文件读取失败'
        console.error(uploadError.value, error)
        isUploading.value = false
      }
      
      try {
        fileReader.readAsDataURL(file)
      } catch (readError) {
        uploadError.value = '调用readAsDataURL时出错'
        console.error(uploadError.value, readError)
        isUploading.value = false
      }
    }
    
    // 在任何情况下，设置上传状态为完成
    isUploading.value = false
    
  } catch (error) {
    uploadError.value = '处理文件时出错'
    console.error(uploadError.value, error)
    isUploading.value = false
  }
}

// 移除已选择的媒体，同时停止上传并清除已上传的分片
function removeMedia(index: number) {
  try {
    if (index >= 0 && index < selectedMedia.value.length) {
      console.log('移除媒体', index)
      console.log('移除前的上传状态:')
      console.log(`- isUploading: ${isUploading.value}`)
      console.log(`- 当前文件: ${uploadController.value.currentFile ? uploadController.value.currentFile.name : '无'}`)
      console.log(`- isCancelled: ${uploadController.value.isCancelled}`)
      console.log(`- isPaused: ${uploadController.value.isPaused}`)
      
      // 1. 获取要移除的媒体
      const media = selectedMedia.value[index]
      
      // 2. 立即标记所有相关媒体为已移除（包括可能有相同URL的其他媒体）
      if (media && media.url) {
        const mediaUrl = media.url
        const mediaName = media.name
        
        selectedMedia.value.forEach((m, i) => {
          if (m.url === mediaUrl || m.name === mediaName) {
            console.log(`标记媒体为已移除: index=${i}, name=${m.name}`)
            m.removed = true
          }
        })
      }
      
      // 3. 强制更新视图，确保UI立即反映变化
      selectedMedia.value = [...selectedMedia.value]
      
      // 4. 保存当前会话信息用于通知后端
      const fileId = uploadController.value.fileId
      const sessionId = uploadController.value.sessionId
      
      // 5. 强制停止所有上传活动
      console.log('执行彻底的清理流程')
      emergencyStopAllUploads()
      
      // 6. 再次确认上传状态已被重置
      isUploading.value = false
      uploadProgress.value = 0
      
      // 7. 通知后端删除已上传的分片
      if (fileId || sessionId) {
        console.log(`通知后端删除已上传分片: fileId=${fileId}, sessionId=${sessionId}`)
        
        // 在实际项目中，这里应该发送请求到后端删除分片
        // 例如:
        /*
        fetch('/api/upload/cancel', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            fileId: fileId,
            sessionId: sessionId,
            fileName: currentFileName
          })
        })
        .then(response => response.json())
        .then(data => {
          console.log('后端删除分片响应:', data);
        })
        .catch(error => {
          console.error('通知后端删除分片失败:', error);
        });
        */
        
        // 模拟后端响应
        console.log('后端已删除所有已上传分片')
      }
      
      // 8. 确保视频不会被重新渲染到页面上
      if (media && media.url) {
        try {
          // 释放URL资源
          URL.revokeObjectURL(media.url)
          console.log(`已释放媒体URL资源: ${media.name}`)
        } catch (e) {
          console.error('释放URL资源时出错:', e)
        }
      }
      
      // 9. 清空上传控制器状态
      uploadController.value = {
        fileId: null,
        isPaused: false,
        isCancelled: true, // 确保设置为已取消状态
        uploadedChunks: new Set<number>(),
        failedChunks: new Map<number, number>(),
        processingChunks: new Set<number>(),
        totalChunks: 0,
        currentFile: null,
        currentFileType: null,
        md5: null,
        uploadStartTime: null,
        uploadSpeed: 0,
        estimatedTimeRemaining: null,
        lastNetworkCheckTime: 0,
        sessionId: `upload-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`
      }
      
      // 10. 输出移除后的状态
      console.log('移除媒体后的上传状态:')
      console.log(`- isUploading: ${isUploading.value}`)
      console.log(`- isCancelled: ${uploadController.value.isCancelled}`)
      console.log(`- isPaused: ${uploadController.value.isPaused}`)
      
      // 11. 清除本地存储的上传状态
      try {
        localStorage.removeItem('uploadState')
        console.log('已清除本地存储的上传状态')
      } catch (error) {
        console.error('清除上传状态失败:', error)
      }
      
      // 12. 延迟后再实际从数组中移除
      setTimeout(() => {
        // 从数组中移除该媒体
        selectedMedia.value = selectedMedia.value.filter(m => !m.removed)
        
        // 再次强制Vue更新视图
        selectedMedia.value = [...selectedMedia.value]
        console.log('延迟后实际移除媒体完成，当前媒体数量:', selectedMedia.value.length)
        
        // 确保计算属性更新
        nextTick(() => {
          console.log('视图已更新，可见媒体数量:', visibleMedia.value.length)
        })
      }, 300)
      
      console.log('移除后媒体列表长度:', selectedMedia.value.length)
    } else {
      console.error('尝试移除不存在的媒体索引:', index)
    }
  } catch (error) {
    console.error('移除媒体时出错:', error)
    
    // 即使出错，也确保重置上传状态
    isUploading.value = false
    uploadProgress.value = 0
    
    // 尝试清除所有计时器
    try {
      const highestId = window.setTimeout(() => {}, 0)
      for (let i = 0; i <= highestId; i++) {
        window.clearTimeout(i)
        window.clearInterval(i)
      }
    } catch (e) {
      console.error('清除计时器时出错:', e)
    }
  }
}

// 发布动态 - 修改为使用统一数据管理
async function publishPost() {
  try {
    // 验证表单
    if (!postForm.value.title.trim()) {
      showToastMessage('请输入标题', 'warning')
      return
    }
    
    if (selectedMedia.value.length === 0) {
      showToastMessage('请至少上传一张图片或视频', 'warning')
      return
    }
    
    // 显示发布中提示
    showToastMessage('正在处理媒体文件，请稍候...', 'info')
    
    // 获取当前日期
    const currentDate = new Date()
    const year = currentDate.getFullYear()
    const month = String(currentDate.getMonth() + 1).padStart(2, '0')
    const day = String(currentDate.getDate()).padStart(2, '0')
    const formattedDate = `${year}-${month}-${day}`
    
    // 收集媒体信息
    const mediaItems = selectedMedia.value.filter(media => !media.removed)
    
    // 提取媒体URL和类型
    const mediaUrls = mediaItems.map(media => media.url || '')
    const mediaTypes = mediaItems.map(media => media.type || 'image')
    
    // 处理媒体URL，确保刷新后可用
    console.log('开始处理媒体URL，共', mediaUrls.length, '个')
    
    // 创建存储媒体的引用和类型
    const processedMediaRefs: string[] = []
    const processedMediaTypes: ('image' | 'video')[] = []
    
    // 处理每个媒体URL
    for (let i = 0; i < mediaUrls.length; i++) {
      const url = mediaUrls[i]
      const type = mediaTypes[i]
      
      try {
        // 生成唯一的媒体引用键
        const mediaKey = `media_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
        
        // 如果是blob URL，转换为data URL
        let processedUrl = url
        if (url.startsWith('blob:')) {
          processedUrl = await blobToDataURL(url, type)
        }
        
        // 确保视频URL包含标记
        if (type === 'video' && !processedUrl.includes('#video/')) {
          const extension = processedUrl.split('.').pop()?.toLowerCase() || 'mp4'
          processedUrl = processedUrl + `#video/${extension}`
        }
        
        // 存储到IndexedDB
        await saveMediaToIndexedDB(mediaKey, processedUrl, type)
        console.log(`已将媒体保存到IndexedDB: ${mediaKey}, 类型: ${type}`)
        
        // 添加引用到列表
        processedMediaRefs.push(mediaKey)
        processedMediaTypes.push(type)
      } catch (error) {
        console.error(`处理媒体 ${i+1}/${mediaUrls.length} 时出错:`, error)
        // 如果处理失败，使用原始URL
        processedMediaRefs.push(url)
        processedMediaTypes.push(type)
      }
    }
    
    if (processedMediaRefs.length === 0) {
      showToastMessage('媒体处理失败，请重新上传', 'error')
      return
    }
    
    // 创建新动态数据
    const newPostData = {
      avatar: getUserAvatar(),
      name: getUserDisplayName(),
      date: formattedDate,
      sportType: postForm.value.sportType || '健身训练',
      distance: postForm.value.distance || '0.00km',
      time: postForm.value.time || '00:00:00',
      calorie: postForm.value.calorie || '0千卡',
      images: processedMediaRefs,
      mediaTypes: processedMediaTypes,
      descTitle: postForm.value.title,
      desc: postForm.value.content || '',
      like: 0,
      comment: 0
    }
    
    console.log('准备发布新动态:', newPostData)
    
    // 使用统一数据管理添加动态（会自动同步到笔记）
    const newPost = addCommunityPost(newPostData)
    
    // 添加到动态列表开头
    circleList.value.unshift(newPost)
    
    // 保存到本地存储
    saveCircleListToStorage()
    
    // 重置分页数据并重新加载
    initData()
    
    console.log('发布成功，当前动态列表长度:', circleList.value.length)
    
    // 切换到韵动圈标签页
    activeTab.value = 'circle'
    
    // 重置表单
    resetForm()
    
    // 关闭上拉菜单
    showSheet.value = false
    
    // 显示成功提示
    showToastMessage('发布成功！已同步到我的笔记', 'success')
  } catch (error) {
    console.error('发布动态时出错:', error)
    showToastMessage('发布失败，请重试', 'error')
  }
}

// 重置表单
function resetForm() {
  postForm.value = {
    title: '',
    content: '',
    sportType: '健身训练',
    distance: '0.00km',
    time: '00:00:00',
    calorie: '0千卡',
  }
  selectedMedia.value = []
  titleCount.value = 0
}

// 重置表单的函数已在上面定义

// 获取视频源URL - 改进处理各种URL格式的能力
function getVideoSrc(mediaUrl: string): string {
  if (!mediaUrl) return '';
  
  try {
    // 首先检查是否是从IndexedDB恢复的视频引用（以media_开头的短字符串）
    if (mediaUrl.startsWith('media_') && mediaUrl.length < 50) {
      // 尝试从IndexedDB加载
      loadMediaFromIndexedDB(mediaUrl).then(storedMedia => {
        if (storedMedia) {
          console.log('从IndexedDB恢复视频:', mediaUrl);
          // 找到对应的视频元素并更新src
          setTimeout(() => {
            const videoElements = document.querySelectorAll(`video[data-key="${mediaUrl}"]`);
            videoElements.forEach(video => {
              if (video instanceof HTMLVideoElement) {
                video.src = storedMedia;
                // 重新加载视频
                video.load();
              }
            });
          }, 0);
          return storedMedia;
        } else {
          // 如果IndexedDB中没有，尝试从localStorage恢复（兼容旧数据）
          const localStorageMedia = localStorage.getItem(mediaUrl);
          if (localStorageMedia) {
            console.log('从localStorage恢复视频:', mediaUrl);
            return getVideoSrc(localStorageMedia); // 递归处理恢复的URL
          }
        }
      }).catch(error => {
        console.error('从IndexedDB加载媒体失败:', error);
      });
      
      // 返回一个临时占位符，稍后会被异步更新
      return mediaUrl;
    }
    
    // 处理包含视频标记的URL
    if (mediaUrl.includes('#video/')) {
      // 提取视频格式
      const format = mediaUrl.split('#video/')[1] || 'mp4';
      const baseUrl = mediaUrl.split('#video/')[0];
      
      // 如果是data URL但没有正确的MIME类型
      if (baseUrl.startsWith('data:') && !baseUrl.includes('data:video/')) {
        // 修复MIME类型
        const fixedUrl = baseUrl
          .replace('data:application/octet-stream', `data:video/${format}`)
          .replace('data:text/plain', `data:video/${format}`);
        
        console.log('修复data URL的MIME类型:', fixedUrl.substring(0, 50) + '...');
        return fixedUrl;
      }
      
      return baseUrl;
    }
    
    // 处理blob URL
    if (mediaUrl.startsWith('blob:')) {
      return mediaUrl;
    }
    
    // 处理data URL
    if (mediaUrl.startsWith('data:')) {
      // 如果是data URL但没有视频MIME类型
      if (!mediaUrl.includes('data:video/')) {
        // 尝试修复MIME类型
        const fixedUrl = mediaUrl
          .replace('data:application/octet-stream', 'data:video/mp4')
          .replace('data:text/plain', 'data:video/mp4');
        
        console.log('修复data URL的MIME类型:', fixedUrl.substring(0, 50) + '...');
        return fixedUrl;
      }
    }
    
    // 处理http/https URL
    if (mediaUrl.startsWith('http')) {
      // 如果是本地开发环境的URL
      if (mediaUrl.includes('localhost')) {
        // 移除查询参数和多余的路径
        if (mediaUrl.includes('#video/mp4')) {
          return mediaUrl.split('#video/mp4')[0];
        }
        if (mediaUrl.includes('video/mp4#video/mp4')) {
          return mediaUrl.split('#video/mp4')[0];
        }
        // 移除可能导致错误的多余路径
        if (mediaUrl.includes('video/mp4video/mp4')) {
          return mediaUrl.replace('video/mp4video/mp4', 'video/mp4');
        }
        
        // 处理重复的localhost路径问题
        if (mediaUrl.indexOf('localhost:5173') !== mediaUrl.lastIndexOf('localhost:5173')) {
          const parts = mediaUrl.split('localhost:5173');
          if (parts.length > 1) {
            return 'http://localhost:5173' + parts[parts.length - 1];
          }
        }
      }
    }
    
    return mediaUrl;
  } catch (error) {
    console.error('处理视频URL时出错:', error, mediaUrl);
    return mediaUrl; // 出错时返回原始URL
  }
}

// 处理视频加载错误
function handleVideoError(event: Event, mediaUrl: string) {
  console.error('视频加载失败:', mediaUrl);
  console.log('尝试修复视频URL:', mediaUrl);
  
  // 尝试修复视频URL
  if (mediaUrl) {
    const videoElement = event.target as HTMLVideoElement;
    
    try {
      // 检查是否是IndexedDB引用
      if (mediaUrl.startsWith('media_') && mediaUrl.length < 50) {
        console.log('检测到媒体引用，尝试从IndexedDB加载:', mediaUrl);
        
        // 设置data-key属性，以便异步加载后能找到这个元素
        videoElement.setAttribute('data-key', mediaUrl);
        
        // 尝试从IndexedDB加载
        loadMediaFromIndexedDB(mediaUrl).then(storedMedia => {
          if (storedMedia) {
            console.log('从IndexedDB成功恢复视频:', mediaUrl);
            videoElement.src = storedMedia;
            videoElement.load();
            return;
          } else {
            // 如果IndexedDB中没有，尝试从localStorage恢复
            const localStorageMedia = localStorage.getItem(mediaUrl);
            if (localStorageMedia) {
              console.log('从localStorage恢复视频:', mediaUrl);
              videoElement.src = localStorageMedia;
              videoElement.load();
              return;
            }
            
            console.log('无法从存储中恢复视频:', mediaUrl);
            showToastMessage('无法加载视频，请重新上传', 'error');
          }
        }).catch(error => {
          console.error('从IndexedDB加载媒体失败:', error);
          showToastMessage('加载视频失败，请刷新重试', 'error');
        });
        
        return;
      }
      
      // 获取修复后的URL
      const fixedUrl = getVideoSrc(mediaUrl);
      
      // 如果修复后的URL与原URL不同，应用修复后的URL
      if (fixedUrl !== mediaUrl) {
        // 应用修复后的URL
        videoElement.src = fixedUrl;
        console.log('尝试修复视频URL:', fixedUrl);
        
        // 重新加载视频
        videoElement.load();
      } else if (mediaUrl.includes('localhost')) {
        // 本地开发环境中的URL可能需要特殊处理
        
        // 尝试修复多重路径问题
        let simplifiedUrl = mediaUrl;
        
        // 移除查询参数
        simplifiedUrl = simplifiedUrl.split('?')[0]; 
        
        // 修复常见的URL错误模式
        if (simplifiedUrl.includes('video/mp4video/mp4')) {
          simplifiedUrl = simplifiedUrl.replace('video/mp4video/mp4', 'video/mp4');
        }
        
        // 处理多重路径
        if (simplifiedUrl.includes('localhost:5173') && simplifiedUrl.indexOf('localhost:5173') !== simplifiedUrl.lastIndexOf('localhost:5173')) {
          // 只保留第一个路径部分
          const parts = simplifiedUrl.split('localhost:5173');
          if (parts.length > 1) {
            simplifiedUrl = 'http://localhost:5173' + parts[1];
          }
        }
        
        // 应用修复后的URL
        console.log('尝试简化本地视频URL:', simplifiedUrl);
        videoElement.src = simplifiedUrl;
        videoElement.load();
        
        // 在控制台显示修复后的URL，方便调试
        console.log('修复后的视频URL:', videoElement.src);
      }
    } catch (error) {
      console.error('修复视频URL失败:', error);
      
      // 尝试使用默认视频
      try {
        // 如果所有修复尝试都失败，显示错误提示
        console.log('无法修复视频URL，显示错误提示');
        showToastMessage('视频加载失败，请刷新页面重试', 'error');
      } catch (e) {
        console.error('显示错误提示失败:', e);
      }
    }
  }
}

// 聊天按钮点击事件，点击后跳转到聊天页面
function openChat(user: UserType) {
  router.push({
    path: '/chat',
    query: { name: user.name, avatar: user.avatar }
  })
}

</script>

<template>
  <!-- 外层容器 -->
  <div class="community" @scroll="throttledHandleScroll">
    <!-- 搜索栏和tab栏 -->
    <div class="top-bar">
      <!-- 搜索框 -->
      <div class="search-box">
        <!-- 搜索图标 - 移到输入框前面 -->
        <span class="icon-search">🔍</span>
        
        <!-- 搜索输入框，添加input事件监听实现防抖 -->
        <input 
          v-model="search" 
          type="text" 
          placeholder="搜索用户名" 
          @input="onSearchInput" 
        />
        
        <!-- 搜索状态指示器 -->
        <span v-if="isSearching" class="search-indicator">搜索中...</span>
        
        <!-- 扫码图标 -->
        <!-- <span class="icon-scan">⎚</span> -->
      </div>
      <!-- tab栏 -->
      <div class="tabs">
        <!-- 遍历tab列表 -->
        <span v-for="tab in tabs" :key="tab.value" :class="['tab', { active: activeTab === tab.value }]"
          @click="activeTab = tab.value; handleTabChange(tab.value)">
          {{ tab.label }}
        </span>
        
        <!-- 清除我的动态按钮 -->
        <span class="clear-my-posts" @click="clearMyPosts">
          清除我的动态
        </span>
      </div>
    </div>
    <!-- tab内容区 -->
    <div class="tab-content" @scroll="throttledHandleScroll">
      <!-- 发现tab内容 -->
      <div v-if="activeTab === 'discover'">
        <!-- 用户列表 -->
        <div class="user-list">
          <!-- 搜索结果为空时的提示 -->
          <div v-if="search.trim() && filteredUsers.length === 0" class="no-search-results">
            没有找到匹配"{{ search }}"的用户
          </div>
          
          <!-- 遍历用户数据 -->
          <div class="user-item" v-for="user in filteredUsers" :key="user.name">
            <!-- 头像，点击跳转到详情页 -->
            <img 
              class="avatar" 
              :src="user.avatar" 
              alt="avatar" 
              @click="goDetail(user)"
              style="cursor: pointer;"
            />
            <!-- 用户信息 -->
            <div class="user-info">
              <!-- 用户名，搜索关键词高亮显示 -->
              <div class="user-name" v-if="search.trim()">
                <span v-html="highlightKeyword(user.name, search)"></span>
              </div>
              <div class="user-name" v-else>{{ user.name }}</div>
              <div class="user-level">Lv：{{ user.level }}</div>
            </div>
            <!-- 操作区：关注按钮和私信按钮 -->
            <div class="user-actions">
              <!-- 关注按钮，宽度固定，和+关注按钮一致 -->
              <button
                class="follow-btn"
                :class="{ followed: user.followed }"
                @click="handleFollow(user)"
              >
                <template v-if="user.followed">已关注</template>
                <template v-else>+关注</template>
              </button>
              <!-- 聊天按钮：已关注时显示为聊天图标 -->
              <button
                v-if="user.followed"
                class="chat-btn"
                @click="openChat(user)"
                title="聊天"
              >
              💬
              </button>
            </div>
          </div>
        </div>
        
        <!-- 加载状态提示 -->
        <div v-if="discoverLoading" class="loading-container">
          <div class="loading-spinner"></div>
          <div class="loading-text">加载中...</div>
        </div>
        
        <!-- 手动加载更多按钮（当自动加载失败时的备用方案） -->
        <div v-if="!discoverLoading && !discoverNoMoreData && filteredUsers.length > 0 && filteredUsers.length < users.length" class="load-more-container">
          <button class="load-more-btn" @click="loadMoreDiscoverData">
            加载更多
          </button>
        </div>
        
        <!-- 无更多数据提示 -->
        <div v-if="discoverNoMoreData && filteredUsers.length > 0" class="no-more-data">
          —— 已经到底啦 ——
        </div>
      </div>
      <!-- 韵动圈tab内容 -->
      <div v-else>
        <!-- 动态卡片列表和悬浮发布按钮包裹在普通容器 -->
        <div class="circle-tab-content" @scroll="throttledHandleScroll">
          <!-- 动态卡片列表 -->
          <div class="circle-list">
            <!-- 单条动态卡片，模拟两条 -->
            <div class="circle-item" v-for="(item, idx) in displayCircleList" :key="idx">
              <!-- 头部：头像、昵称、日期 -->
              <div class="circle-header">
                <img 
                  class="circle-avatar" 
                  :src="item.avatar" 
                  alt="avatar" 
                  @click="goDetail({ name: item.name, avatar: item.avatar, level: 0, followed: false })"
                  style="cursor: pointer;"
                />
                <div class="circle-user-info">
                  <div class="circle-name">{{ item.name }}</div>
                  <div class="circle-date">{{ item.date }}</div>
                </div>
              </div>
              <!-- 运动类型及数据 -->
              <div class="circle-sport">
                <span class="sport-icon">🏃‍♂️</span>
                <span class="sport-type">{{ item.sportType }}</span>
                <div class="sport-data">
                  <div>
                    <div class="data-label">运动距离</div>
                    <div class="data-value">{{ item.distance }}</div>
                  </div>
                  <div>
                    <div class="data-label">运动时间</div>
                    <div class="data-value">{{ item.time }}</div>
                  </div>
                  <div>
                    <div class="data-label">运动消耗</div>
                    <div class="data-value">{{ item.calorie }}</div>
                  </div>
                </div>
              </div>
              <!-- 图片和视频区 -->
              <div class="circle-images">
                <!-- 检测文件类型并相应渲染图片或视频 -->
                <template v-for="(media, i) in item.images" :key="i">
                  <!-- 如果是视频文件 (.mp4, .webm 等) 或者URL包含blob且文件名包含视频扩展名 -->
                  <video 
                    v-if="(typeof media === 'string' && (
                      media.endsWith('.mp4') || 
                      media.endsWith('.webm') || 
                      media.endsWith('.mov') || 
                      media.includes('video/mp4') || 
                      media.includes('video/webm') ||
                      media.includes('#video/') ||
                      (item.mediaTypes && item.mediaTypes[i] === 'video')
                    ))" 
                    :src="getVideoSrc(media)" 
                    :data-key="media.startsWith('media_') && media.length < 50 ? media : ''"
                    class="circle-video" 
                    controls 
                    preload="metadata"
                    playsinline
                    poster=""
                    @error="handleVideoError($event, media)"
                  ></video>
                  <!-- 否则作为图片渲染 -->
                  <img v-else :src="media" class="circle-img" />
                </template>
              </div>
              <!-- 描述区 -->
              <div class="circle-desc">
                <div class="desc-title">{{ item.descTitle }}</div>
                <div class="desc-content">{{ item.desc }}</div>
              </div>
              <!-- 操作区：点赞、评论、分享 -->
              <div class="circle-actions">
                <span class="action"><span class="icon">👍</span> {{ item.like }}</span>
                <span class="action"><span class="icon">💬</span> {{ item.comment }}</span>
                <span class="action"><span class="icon">···</span></span>
                <span class="action"><span class="icon">🔗</span></span>
              </div>
            </div>
          </div>
          
          <!-- 加载状态提示 -->
          <div v-if="loading" class="loading-container">
            <div class="loading-spinner"></div>
            <div class="loading-text">加载中...</div>
          </div>
          
          <!-- 手动加载更多按钮（当自动加载失败时的备用方案） -->
          <div v-if="!loading && !noMoreData && displayCircleList.length > 0 && displayCircleList.length < circleList.length" class="load-more-container">
            <button class="load-more-btn" @click="loadMoreData">
              加载更多
            </button>
          </div>
          
          <!-- 无更多数据提示 -->
          <div v-if="noMoreData && displayCircleList.length > 0" class="no-more-data">
            —— 已经到底啦 ——
          </div>
        </div>
        <!-- 右下角悬浮按钮，始终浮在页面右下角，z-index高于菜单 -->
        <button class="circle-fab-fixed" :class="{ share: showSheet }" @click="showSheet = true">
          <span v-if="!showSheet">✏️</span>
          <span v-else>
            <!-- 正确使用Element Plus图标 -->
            <Position class="fab-img-icon" />
          </span>
        </button>
        <!-- 上拉菜单遮罩和内容，z-index低于悬浮按钮 -->
        <div v-if="showSheet" class="sheet-mask" @click.self="showSheet = false">
          <div class="sheet-panel">
            <!-- 关闭按钮 -->
            <span class="sheet-close" @click="showSheet = false">×</span>
            <!-- 菜单内容区，示例布局 -->
            <div class="sheet-content">
              <!-- 上传状态和控制按钮 -->
              <div v-if="isUploading" class="upload-controls-container">
                <div class="upload-status">
                  <div class="upload-status-icon">
                    <span>⬆</span>
                </div>
                  <div class="upload-status-info">
                    <div class="upload-status-title">
                      正在上传文件
                    </div>
                    <div class="upload-status-detail">
                      {{ uploadController.currentFile ? uploadController.currentFile.name : '文件' }} - {{ uploadProgress }}%
                    </div>
                    <div class="upload-status-extra" v-if="uploadController.uploadSpeed > 0">
                      <span class="upload-speed">{{ formatFileSize(uploadController.uploadSpeed) }}/s</span>
                      <span class="upload-time" v-if="uploadController.estimatedTimeRemaining !== null">
                        剩余时间: {{ formatTime(uploadController.estimatedTimeRemaining) }}
                      </span>
                    </div>
                  </div>
                </div>
              </div>
              
              <!-- 错误提示 -->
              <div v-if="uploadError" class="upload-error-container">
                <div class="upload-error-icon">⚠️</div>
                <div class="upload-error-message">{{ uploadError }}</div>
                <button 
                  v-if="uploadController.currentFile" 
                  @click="retryUpload" 
                  class="upload-retry-btn"
                >
                  重试
                </button>
              </div>
              
              <!-- 上传区域和预览 -->
              <div class="media-upload-container">
                <!-- 没有媒体时显示上传占位符 -->
                <div v-if="selectedMedia.length === 0" class="upload-area">
                  <input 
                    type="file" 
                    accept="image/jpeg,image/png,image/gif,image/webp,video/mp4,video/webm,video/quicktime" 
                    style="display: none;" 
                    id="fileInput"
                    @change="handleFileSelect" 
                  />
                  <label for="fileInput" class="upload-icon-box">
                    <span class="sheet-img-icon">📷</span>
                    <div class="upload-text">上传图片/视频</div>
                    <div class="upload-hint">支持JPG、PNG、GIF、WEBP、MP4、WEBM格式</div>
                    <div class="upload-hint">最大文件大小：{{ formatFileSize(MAX_FILE_SIZE) }}</div>
                  </label>
                </div>

                <!-- 已上传媒体预览 -->
                <div v-else class="media-preview-area">
                    <!-- 使用计算属性过滤媒体，避免使用v-show导致不必要的渲染 -->
                    <!-- 添加v-memo指令，只有当媒体对象或上传状态变化时才重新渲染 -->
                    <div v-for="(media, index) in visibleMedia" 
                         :key="`media-${index}-${media.name}`" 
                         v-memo="[media.url, media.name]"
                         class="media-preview">
                    <!-- 图片预览 -->
                    <img v-if="media.type === 'image'" :src="media.url" class="media-preview-item" />
                    <!-- 视频预览 - 添加性能优化属性 -->
                      <video 
                        v-if="media.type === 'video'" 
                        :src="getVideoSrc(media.url)" 
                        class="media-preview-item" 
                        controls 
                        preload="metadata" 
                        muted
                        playsinline
                        disablePictureInPicture
                        controlsList="nodownload nofullscreen"
                        @error="handleVideoError($event, media.url)"
                      ></video>
                    
                    <!-- 上传中的进度条覆盖层 -->
                    <div v-if="isUploading && uploadController.currentFile && uploadController.currentFile.name === media.name" 
                         class="media-upload-overlay">
                      <div class="media-upload-progress">
                        <div class="upload-progress-text-small">{{ uploadProgress }}%</div>
                        <div class="media-progress-bar">
                          <div class="media-progress-fill" :style="{width: uploadProgress + '%'}"></div>
                        </div>
                      </div>
                    </div>
                    
                    <!-- 文件信息 -->
                    <div class="media-info">
                      <div class="media-name">{{ media.name }}</div>
                      <div class="media-size">{{ formatFileSize(media.size) }}</div>
                    </div>
                    <!-- 删除按钮 -->
                    <div class="media-delete" @click="removeMedia(index)">×</div>
                  </div>

                  <!-- 已有媒体时显示的添加按钮 -->
                  <label v-if="selectedMedia.length < 4" class="media-add-button">
                    <input 
                      type="file" 
                      accept="image/jpeg,image/png,image/gif,image/webp,video/mp4,video/webm,video/quicktime" 
                      style="display: none;" 
                      @change="handleFileSelect" 
                    />
                    <div class="add-icon">+</div>
                  </label>
                </div>
              </div>
              
              <!-- 表单区域 -->
              <div class="post-form">
                <!-- 标题输入框 -->
                <div class="form-group">
                  <input 
                    class="sheet-title" 
                    maxlength="30" 
                    placeholder="输入标题" 
                    v-model.lazy="postForm.title" 
                    @input="updateTitleCount"
                  />
                  <div class="sheet-title-count">{{ titleCount }}/30</div>
                </div>
                
                <!-- 内容输入框 -->
                <div class="form-group">
                  <textarea 
                    class="sheet-desc" 
                    placeholder="输入内容，分享动态" 
                    v-model.lazy="postForm.content"
                  ></textarea>
                </div>
                
                <!-- 运动数据输入区 -->
                <div class="form-group">
                  <div class="form-row">
                    <div class="form-label">运动类型</div>
                    <input type="text" v-model.lazy="postForm.sportType" class="form-input" />
                  </div>
                  <div class="form-row">
                    <div class="form-label">运动距离</div>
                    <input type="text" v-model.lazy="postForm.distance" class="form-input" />
                  </div>
                  <div class="form-row">
                    <div class="form-label">运动时间</div>
                    <input type="text" v-model.lazy="postForm.time" class="form-input" />
                  </div>
                  <div class="form-row">
                    <div class="form-label">消耗热量</div>
                    <input type="text" v-model.lazy="postForm.calorie" class="form-input" />
                  </div>
                </div>
                
                <!-- 发布按钮 -->
                <button class="publish-btn" @click="publishPost">发布动态</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 添加Toast提示组件 -->
  <div v-if="showToast" class="toast-message" :class="toastType">
    {{ toastMessage }}
  </div>
</template>

<style scoped>
/* 外层容器样式 */
.community {
  background: #fff;
  min-height: 100vh;
  font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
  overflow-x: hidden; /* 防止水平滚动 */
  overflow-y: auto; /* 允许垂直滚动 */
  position: relative;
  padding: 0;
  margin: 0;
  /* 启用平滑滚动 */
  scroll-behavior: smooth;
  height: 100vh; /* 设置高度为视口高度 */
}

/* 顶部栏样式 - 使用fixed定位 */
.top-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background: #fff;
  padding: 12px 16px 2px 16px; /* 调整内边距 */
  box-shadow: 0 2px 10px rgba(0,0,0,0.08); /* 增强阴影 */
  /* 调整高度 */
  height: 86px; /* 微调高度 */
  box-sizing: border-box;
  /* 添加微妙动画效果 */
  transition: box-shadow 0.3s ease, height 0.3s ease;
  /* 设置宽度，防止页面横向滚动 */
  width: 100%;
  max-width: 100%;
}

/* 搜索框样式 */
.search-box {
  display: flex;
  align-items: center;
  position: relative;
  margin-bottom: 10px; /* 增加间距 */
}

.search-box input {
  flex: 1;
  height: 36px; /* 增加高度 */
  border-radius: 18px; /* 增加圆角 */
  border: 1px solid #e8e8e8; /* 淡化边框 */
  padding: 0 36px 0 40px; /* 增加左侧内边距，为搜索图标留出更多空间 */
  font-size: 15px;
  outline: none;
  /* 防止iOS默认样式 */
  -webkit-appearance: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); /* 添加轻微阴影 */
  transition: all 0.3s ease; /* 添加过渡效果 */
}

.search-box input:focus {
  border-color: #1abc9c;
  box-shadow: 0 0 0 3px rgba(26, 188, 156, 0.15); /* 增强焦点效果 */
}

.icon-search {
  position: absolute;
  left: 14px; /* 稍微调整位置，避免遮挡文字 */
  font-size: 16px;
  color: #aaa; /* 淡化颜色 */
  transition: color 0.3s ease; /* 添加过渡效果 */
  pointer-events: none; /* 确保图标不会拦截点击事件 */
}

/* 添加搜索指示器样式 */
.search-indicator {
  position: absolute;
  right: 14px;
  font-size: 12px;
  color: #1abc9c;
  animation: pulse 1.5s infinite;
}

.search-box input:focus + .icon-search {
  color: #1abc9c; /* 输入框获得焦点时图标变色 */
}

/* tab栏样式 */
.tabs {
  display: flex;
  gap: 24px; /* 增加间距 */
  font-size: 17px;
  margin-bottom: 6px;
  /* 防止tab收缩 */
  flex-shrink: 0;
  padding: 0 4px; /* 添加内边距 */
}

.tab {
  color: #888;
  cursor: pointer;
  padding-bottom: 6px; /* 增加内边距 */
  border-bottom: 2px solid transparent;
  transition: color 0.3s, border-color 0.3s; /* 增加过渡时间 */
  position: relative; /* 添加相对定位，用于伪元素 */
}

.tab.active {
  color: #1abc9c;
  border-bottom: 2px solid #1abc9c;
  font-weight: bold;
}

/* 添加悬停效果 */
.tab:hover {
  color: #1abc9c;
}

/* 添加下划线动画效果 */
.tab::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 2px;
  background-color: #1abc9c;
  transition: width 0.3s ease;
}

.tab:hover::after {
  width: 100%;
}

.tab.active::after {
  width: 100%;
}

/* 清除我的动态按钮 */
.clear-my-posts {
  margin-left: auto;
  padding: 4px 10px;
  background-color: #ff5252;
  color: white;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.clear-my-posts:hover {
  background-color: #ff1a1a;
  transform: translateY(-1px);
  box-shadow: 0 2px 5px rgba(255, 82, 82, 0.3);
}

/* tab内容区域 - 添加顶部内边距避免被fixed的顶部栏遮挡 */
.tab-content {
  /* 顶部留出空间，精确匹配顶部栏高度 */
  padding-top: 86px; /* 与顶部栏高度保持一致 */
  width: 100%;
  /* 添加底部内边距，避免内容被底部导航栏遮挡 */
  padding-bottom: 70px;
  overflow-y: auto; /* 允许垂直滚动 */
  height: calc(100vh - 86px); /* 设置高度为视口高度减去顶部栏高度 */
}

/* 优化滚动条样式 */
.tab-content::-webkit-scrollbar {
  width: 4px;
}

.tab-content::-webkit-scrollbar-track {
  background: #f1f1f1;
}

.tab-content::-webkit-scrollbar-thumb {
  background: #bbb;
  border-radius: 2px;
}

.tab-content::-webkit-scrollbar-thumb:hover {
  background: #1abc9c;
}

/* 用户列表样式 */
.user-list {
  margin-top: 6px;
  padding: 0 16px;
  /* 确保列表底部有足够空间 */
  padding-bottom: 60px;
}

.user-item {
  display: flex;
  align-items: center;
  margin-bottom: 22px; /* 增加间距 */
  padding: 8px; /* 添加内边距 */
  border-radius: 12px; /* 添加圆角 */
  transition: background 0.2s; /* 添加背景过渡效果 */
}

.user-item:hover {
  background: #f9f9f9; /* 悬停背景效果 */
}

.avatar {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  object-fit: cover;
  margin-right: 14px;
  border: 2px solid #f2f2f2;
  transition: transform 0.2s, border-color 0.2s; /* 添加过渡效果 */
}

.avatar:hover {
  transform: scale(1.05); /* 悬停放大效果 */
  border-color: #1abc9c; /* 悬停边框颜色 */
}

.user-info {
  flex: 1;
}

.user-name {
  font-size: 16px;
  font-weight: 500;
  color: #222;
  transition: color 0.2s; /* 添加过渡效果 */
}

.user-item:hover .user-name {
  color: #1abc9c; /* 悬停时用户名变色 */
}

.user-level {
  font-size: 13px;
  color: #888;
  margin-top: 2px;
}

/* 用户操作区容器 */
.user-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px; /* 按钮和图标间距 */
  min-width: 130px; /* 保证操作区宽度一致 */
}

.follow-btn {
  width: 90px; /* 固定宽度，和+关注按钮一致 */
  height: 38px;
  background: #1abc9c;
  color: #fff;
  border: none;
  border-radius: 24px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.follow-btn.followed {
  background: #e0e0e0;
  color: #888;
}

.chat-btn {
  background: #fff;
  color: #1abc9c;
  border: 1px solid #1abc9c;
  border-radius: 50%;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  cursor: pointer;
  transition: all 0.3s;
  padding: 0;
}
.chat-btn:hover {
  background: #1abc9c;
  color: #fff;
}

/* 韵动圈tab内容区相对定位 */
.circle-tab-content {
  position: relative;
  min-height: 400px;
  /* 添加额外底部间距，避免被底部导航栏遮挡 */
  padding-bottom: 80px;
  overflow-y: auto; /* 允许垂直滚动 */
  height: 100%; /* 设置高度为100% */
}

/* 优化动态卡片间距和阴影 */
.circle-list {
  padding: 0 16px 70px 16px;
}

.circle-item {
  background: #fff;
  border-radius: 14px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
  padding: 18px 14px 14px 14px;
  margin-bottom: 22px;
  transition: transform 0.3s ease, box-shadow 0.3s ease; /* 添加过渡效果 */
}

.circle-item:hover {
  transform: translateY(-2px); /* 悬停时上浮效果 */
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); /* 悬停时增强阴影 */
}

/* 悬浮发布按钮fixed定位在页面右下角，不随内容滚动 */
.circle-fab-fixed {
  position: fixed;
  right: 24px;
  bottom: 88px;
  /* 增加z-index确保按钮在前面 */
  z-index: 1001;
  /* 预留底部导航高度 */
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #1abc9c;
  color: #fff;
  font-size: 28px;
  border: none;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16); /* 增强阴影 */
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease; /* 平滑过渡 */
}

.circle-fab-fixed.share {
  background: linear-gradient(135deg, #a8ff78 0%, #78ffd6 100%);
  color: #1abc9c;
}

.circle-fab-fixed:hover {
  background: #16a085; /* 深色悬停效果 */
  transform: translateY(-3px) scale(1.05); /* 悬停时上浮放大效果 */
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); /* 悬停时增强阴影 */
}

.circle-header {
  display: flex;
  align-items: center;
  margin-bottom: 12px; /* 增加间距 */
}

.circle-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  margin-right: 10px;
  border: 2px solid #f2f2f2; /* 添加边框 */
  transition: transform 0.2s, border-color 0.2s; /* 添加过渡效果 */
}

.circle-avatar:hover {
  transform: scale(1.05); /* 悬停时放大效果 */
  border-color: #1abc9c; /* 悬停时边框颜色 */
}

.circle-user-info {
  display: flex;
  flex-direction: column;
}

.circle-name {
  font-size: 15px;
  font-weight: 500;
  color: #222;
  transition: color 0.2s; /* 添加过渡效果 */
}

.circle-item:hover .circle-name {
  color: #1abc9c; /* 悬停时用户名变色 */
}

.circle-date {
  font-size: 12px;
  color: #aaa;
}

.circle-sport {
  display: flex;
  align-items: center;
  margin-bottom: 12px; /* 增加间距 */
  margin-top: 2px;
  background: #f9f9f9; /* 添加背景色 */
  padding: 8px 12px; /* 添加内边距 */
  border-radius: 8px; /* 添加圆角 */
}

.sport-icon {
  font-size: 18px;
  margin-right: 6px;
  color: #1abc9c; /* 图标使用主题色 */
}

.sport-type {
  font-size: 14px;
  font-weight: 500;
  margin-right: 12px;
  color: #1abc9c; /* 使用主题色 */
}

.sport-data {
  display: flex;
  gap: 18px;
}

.data-label {
  font-size: 12px;
  color: #888;
}

.data-value {
  font-size: 13px;
  font-weight: 500;
  color: #222;
}

.circle-images {
  display: flex;
  gap: 8px;
  margin: 12px 0; /* 增加间距 */
}

.circle-img {
  width: 48%;
  border-radius: 12px; /* 增加圆角 */
  object-fit: cover;
  max-height: 120px; /* 增加高度 */
  transition: transform 0.3s ease; /* 添加过渡效果 */
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); /* 添加轻微阴影 */
}

.circle-img:hover {
  transform: scale(1.02); /* 悬停时放大效果 */
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); /* 增强阴影 */
}

/* 视频样式 */
.circle-video {
  width: 100%;
  border-radius: 12px;
  object-fit: cover;
  max-height: 180px; /* 视频稍微高一点 */
  transition: transform 0.3s ease;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
  background-color: #000; /* 黑色背景 */
}

.circle-video:hover {
  transform: scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.circle-desc {
  margin-bottom: 12px; /* 增加间距 */
}

.desc-title {
  font-size: 16px; /* 增大字号 */
  font-weight: 600; /* 增加字重 */
  color: #222;
  margin-bottom: 4px; /* 添加间距 */
}

.desc-content {
  font-size: 14px; /* 增大字号 */
  color: #666; /* 颜色加深 */
  line-height: 1.4; /* 增加行高 */
}

.circle-actions {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 15px;
  color: #888;
  padding-top: 8px; /* 添加顶部内边距 */
  border-top: 1px solid #f0f0f0; /* 添加顶部边框 */
}

.action {
  display: flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  transition: color 0.2s ease; /* 添加过渡效果 */
}

.action:hover {
  color: #1abc9c; /* 悬停时颜色变化 */
}

.icon {
  font-size: 18px; /* 增大图标 */
}

/* 上拉菜单遮罩 */
.sheet-mask {
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,0.25); /* 增加不透明度 */
  z-index: 200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  backdrop-filter: blur(3px); /* 添加模糊效果 */
  -webkit-backdrop-filter: blur(3px);
}

/* 上拉菜单面板 */
.sheet-panel {
  width: 96vw;
  max-width: 420px;
  min-height: 340px;
  background: #fff;
  border-radius: 24px 24px 0 0;
  box-shadow: 0 4px 24px rgba(0,0,0,0.15);
  padding: 18px 16px 90px 16px; /* 增加底部内边距，为按钮腾出空间 */
  position: relative;
  animation: sheetUp 0.25s cubic-bezier(.4,1.6,.6,1) 1;
  /* 设置最大高度，允许内容滚动 */
  max-height: 80vh;
  overflow-y: auto;
}

@keyframes sheetUp {
  from { transform: translateY(100%); opacity: 0.8; }
  to { transform: translateY(0); opacity: 1; }
}

/* 关闭按钮 */
.sheet-close {
  position: absolute;
  right: 18px;
  top: 12px;
  font-size: 28px;
  color: #888;
  cursor: pointer;
  z-index: 2;
  transition: color 0.2s, transform 0.2s; /* 添加过渡效果 */
}

.sheet-close:hover {
  color: #1abc9c; /* 悬停时颜色变化 */
  transform: rotate(90deg); /* 悬停时旋转效果 */
}

/* 菜单内容区样式示例 */
.sheet-content {
  margin-top: 18px;
}

.sheet-imgs {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap; /* 允许换行 */
}

/* 上传区域容器 */
.media-upload-container {
  width: 100%;
  margin-bottom: 20px;
}

/* 上传占位符样式 - 虚线框 */
.upload-placeholder {
  width: 100%;
  height: 200px;
  border-radius: 8px;
  border: 2px dashed #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
  background-color: #f9f9f9;
  cursor: pointer;
  transition: all 0.3s ease;
}

.upload-placeholder:hover {
  border-color: #1abc9c;
  background-color: #f0fbf8;
}

.upload-icon-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.upload-text {
  font-size: 14px;
  margin-top: 10px;
  color: #777;
}

.sheet-img-icon {
  font-size: 32px;
}

/* 媒体预览区域 */
.media-preview-area {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
}

/* 媒体预览样式 */
.media-preview {
  position: relative;
  width: calc(50% - 6px);
  height: 180px;
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

/* 视频预览特殊样式 */
.video-preview {
  border: 2px dashed #1abc9c;
  box-shadow: 0 2px 12px rgba(26, 188, 156, 0.15);
  padding: 2px;
}

.video-item {
  border-radius: 6px;
}

.media-preview-item {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 媒体上传进度覆盖层 */
.media-upload-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  transition: background-color 0.3s ease;
}

.media-upload-progress {
  width: 80%;
  text-align: center;
}

.upload-progress-text-small {
  color: #fff;
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 8px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}

.media-progress-bar {
  height: 6px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
  overflow: hidden;
}

.media-progress-fill {
  height: 100%;
  background: #1abc9c;
  border-radius: 3px;
  transition: width 0.3s ease, background-color 0.3s ease;
}

.media-progress-fill.paused {
  background: #f39c12; /* 暂停状态显示为橙色 */
  animation: pulse-paused 1.5s infinite;
}

.media-progress-fill.cancelled {
  background: #e74c3c; /* 取消状态显示为红色 */
  animation: none;
  width: 100% !important; /* 强制显示满进度条 */
  opacity: 0.5;
}

/* 媒体上传覆盖层样式 */
.media-upload-overlay {
  background: rgba(0, 0, 0, 0.5);
  transition: background-color 0.3s ease;
}

/* 控制图标样式 */
.control-icon {
  font-size: 14px;
}

.media-delete {
  position: absolute;
  right: 8px;
  top: 8px;
  width: 28px;
  height: 28px;
  background: rgba(0,0,0,0.6);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 18px;
  z-index: 3; /* 确保在进度条之上 */
}

/* 添加更多媒体的按钮 */
.media-add-button {
  width: calc(50% - 6px);
  height: 180px;
  border-radius: 8px;
  border: 2px dashed #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f9f9f9;
  cursor: pointer;
  transition: all 0.3s ease;
}

.media-add-button:hover {
  border-color: #1abc9c;
  background: #f0fbf8;
}

.add-icon {
  font-size: 40px;
  color: #999;
  transition: color 0.3s;
}

.media-add-button:hover .add-icon {
  color: #1abc9c;
}

/* 上传进度条样式 */
.upload-progress-container {
  width: 100%;
  margin-bottom: 16px;
  padding: 10px;
  background: #f5f5f5;
  border-radius: 8px;
}

.upload-progress-text {
  font-size: 14px;
  color: #666;
  margin-bottom: 8px;
}

.upload-progress-bar {
  height: 8px;
  background: #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}

.upload-progress-fill {
  height: 100%;
  background: #1abc9c;
  border-radius: 4px;
  transition: width 0.3s ease;
}

/* 表单样式 */
.post-form {
  margin-top: 20px;
}

.form-group {
  margin-bottom: 20px;
}

.form-row {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
}

.form-label {
  width: 80px;
  font-size: 15px;
  color: #666;
}

.form-input {
  flex: 1;
  border: none;
  border-bottom: 1px solid #eee;
  font-size: 15px;
  padding: 6px 0;
  outline: none;
  background: transparent;
  transition: border-color 0.3s;
}

.form-input:focus {
  border-color: #1abc9c;
}

.sheet-title {
  width: 100%;
  border: none;
  border-bottom: 1px solid #eee;
  font-size: 16px;
  padding: 8px 0;
  margin-bottom: 2px;
  outline: none;
  font-weight: 500;
  transition: border-color 0.3s;
}

.sheet-title:focus {
  border-color: #1abc9c;
}

.sheet-title-count {
  font-size: 12px;
  color: #bbb;
  text-align: right;
  margin-top: 4px;
}

.sheet-desc {
  width: 100%;
  min-height: 80px;
  border: 1px solid #eee;
  border-radius: 8px;
  padding: 10px;
  font-size: 15px;
  color: #444;
  outline: none;
  resize: none;
  background: transparent;
  transition: border-color 0.3s;
}

.sheet-desc:focus {
  border-color: #1abc9c;
}

/* 发布按钮 - 固定在底部 */
.publish-btn {
  width: calc(100% - 32px);
  background: #1abc9c;
  color: #fff;
  border: none;
  border-radius: 24px;
  padding: 14px 0;
  font-size: 17px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 4px 12px rgba(26, 188, 156, 0.25);
  /* 固定定位在底部 */
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 1002; /* 确保在最上层 */
  max-width: 400px;
}

.publish-btn:hover {
  background: #16a085;
  transform: translateX(-50%) translateY(-2px);
  box-shadow: 0 6px 16px rgba(26, 188, 156, 0.35);
}

.fab-img-icon {
  width: 32px;
  height: 32px;
  display: block;
}

/* 覆盖element-plus搜索框样式 */
:deep(.search-box) {
  margin-bottom: 10px;
  border-radius: 16px;
}
/* 覆盖element-plus tabs样式 */
:deep(.tabs) {
  margin-bottom: 10px;
}
:deep(.el-tabs__item.is-active) {
  color: #1abc9c !important;
}
:deep(.el-tabs__active-bar) {
  background: #1abc9c !important;
}

/* 加载状态容器 */
.loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px 0;
  width: 100%;
}

/* 加载动画 */
.loading-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(26, 188, 156, 0.2);
  border-top-color: #1abc9c;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin-bottom: 10px;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.loading-text {
  font-size: 14px;
  color: #666;
  font-weight: 500;
}

/* 无更多数据提示 */
.no-more-data {
  text-align: center;
  padding: 20px 0;
  color: #999;
  font-size: 14px;
  width: 100%;
}

/* 手动加载更多按钮 */
.load-more-container {
  text-align: center;
  padding: 10px 0;
  color: #666;
  font-size: 14px;
  width: 100%;
}

.load-more-btn {
  background: #f0f0f0;
  color: #666;
  border: none;
  border-radius: 4px;
  padding: 8px 16px;
  cursor: pointer;
  transition: background 0.2s;
}

.load-more-btn:hover {
  background: #e0e0e0;
}

/* 错误提示样式 */
.upload-error-container {
  margin-bottom: 16px;
  padding: 8px;
  border: 1px dashed #ff7b7b;
  border-radius: 4px;
  background-color: #fff8f8;
}

.upload-error-icon {
  margin-right: 8px;
  color: #ff7b7b;
}

.upload-error-message {
  font-size: 14px;
  color: #333;
}

/* 上传控制按钮样式 */
.upload-controls {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}

.upload-control-btn {
  background: #1abc9c;
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 6px 12px;
  cursor: pointer;
  transition: background 0.2s;
}

.upload-control-btn:hover {
  background: #16a085;
}

.pause-btn {
  margin-right: 10px;
}

.resume-btn {
  margin-right: 10px;
}

.cancel-btn {
  margin-right: 10px;
}

/* 上传信息样式 */
.upload-info {
  margin-top: 10px;
  font-size: 14px;
  color: #666;
}

.upload-file-name {
  margin-bottom: 5px;
}

.upload-file-size {
  margin-bottom: 5px;
}

.upload-chunks-info {
  margin-bottom: 5px;
}

.upload-retry-btn {
  background: #1abc9c;
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 6px 12px;
  cursor: pointer;
  transition: background 0.2s;
}

.upload-retry-btn:hover {
  background: #16a085;
}

.upload-hint {
  font-size: 12px;
  color: #888;
  margin-top: 4px;
}

.upload-features {
  display: flex;
  flex-direction: column;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed #ddd;
}

.feature-item {
  font-size: 13px;
  color: #1abc9c;
  margin: 3px 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 上传进度显示 */
.upload-progress-inline {
  background: #f9f9f9;
  padding: 15px;
  border-radius: 8px;
  text-align: center;
  width: 100%;
  margin-bottom: 15px;
  border: 1px solid #eee;
}

.upload-progress-text {
  font-size: 16px;
  color: #333;
  margin-bottom: 15px;
}

.upload-progress-bar {
  height: 6px;
  background: #f0f0f0;
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 10px;
}

.upload-progress-fill {
  height: 100%;
  background: #1abc9c;
  border-radius: 3px;
  transition: width 0.3s ease;
}

.upload-controls-container {
  margin-bottom: 15px;
  background: #f8f8f8;
  padding: 15px;
  border-radius: 10px;
  border: 1px solid #eee;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.upload-status {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
}

.upload-status-icon {
  width: 36px;
  height: 36px;
  background: #1abc9c;
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  margin-right: 12px;
  animation: pulse 1.5s infinite;
}

.upload-status-icon.paused {
  background: #f39c12;
  animation: none;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(26, 188, 156, 0.4);
  }
  70% {
    box-shadow: 0 0 0 8px rgba(26, 188, 156, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(26, 188, 156, 0);
  }
}

.upload-status-info {
  flex: 1;
}

.upload-status-title {
  font-size: 16px;
  font-weight: 500;
  color: #333;
  margin-bottom: 4px;
}

.upload-status-detail {
  font-size: 14px;
  color: #777;
}

.upload-status-extra {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: #888;
  margin-top: 4px;
}

.upload-speed {
  color: #1abc9c;
  font-weight: 500;
}

.upload-time {
  color: #777;
}

/* 全局控制按钮已移除 */

/* 已经被global-control-btn和media-control-btn替代 */

.upload-area {
  width: 100%;
  height: 200px;
  border: 2px dashed #1abc9c;
  border-radius: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  color: #888;
  cursor: pointer;
  transition: all 0.3s ease;
  margin-bottom: 20px;
}

.upload-area:hover {
  border-color: #16a085;
  background-color: #f0fbf8;
}

.upload-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.upload-icon-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.upload-text {
  font-size: 14px;
  margin-top: 10px;
  color: #777;
}

.sheet-img-icon {
  font-size: 32px;
  color: #1abc9c;
}

.upload-hint {
  font-size: 12px;
  color: #888;
  margin-top: 4px;
}

/* 上传进度弹窗中的预览区域 */
.upload-area-preview {
  width: 100%;
  height: 180px;
  border: 2px dashed #1abc9c;
  border-radius: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  color: #888;
  margin-top: 20px;
  background-color: #f9f9f9;
}

.upload-icon-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

/* 上传区域样式已在上方定义 */

/* Toast提示样式 */
.toast-message {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  padding: 10px 20px;
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  font-weight: 500;
  z-index: 2000;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  animation: fadeIn 0.3s, fadeOut 0.3s 2.7s;
  max-width: 80%;
  text-align: center;
}

.toast-message.success {
  background-color: #1abc9c;
}

.toast-message.error {
  background-color: #e74c3c;
}

.toast-message.warning {
  background-color: #f39c12;
}

.toast-message.info {
  background-color: #3498db;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translate(-50%, -20px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

@keyframes fadeOut {
  from { opacity: 1; transform: translate(-50%, 0); }
  to { opacity: 0; transform: translate(-50%, -20px); }
}

/* 搜索结果高亮样式 */
.highlight {
  color: #1abc9c;
  font-weight: bold;
}

/* 搜索结果为空提示 */
.no-search-results {
  text-align: center;
  padding: 20px;
  color: #777;
  font-size: 14px;
}

/* 聊天按钮样式 */
.chat-btn {
  background: #fff;
  color: #1abc9c;
  border: 1px solid #1abc9c;
  border-radius: 50%;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: 8px;
  font-size: 20px;
  cursor: pointer;
  transition: all 0.3s;
}
.chat-btn:hover {
  background: #1abc9c;
  color: #fff;
}
</style>